jeroenst / tasmota_scripts

1 stars 0 forks source link

smart meter script not working #1

Open georgewahba opened 2 months ago

georgewahba commented 2 months ago

hello, I have the same smart stuff dongle as you and I am trying to use it with Tasmota, when I add the berry scrips as you it gives me an error, are you able to help me make my p1 meter to work

CleanShot 2024-04-18 at 11 25 17

jeroenst commented 2 months ago

Hi!

This is work in progress, I try to catch up of this next week.

georgewahba commented 2 months ago

cool, will it work immidiatly after running berry and connecting to mqtt, or wil I have to do some different configuration

jeroenst commented 2 months ago

My target is that it will publish values like any other sensor in Tasmota and the values are also visible on the main page

georgewahba commented 2 months ago

cool, exactly what I want, I just want to publish it trough mqtt as well

georgewahba commented 2 months ago

I continued working and expanding on your code, this is what I got so far. I was able to solve all the errors it was giving like the one I had before, but I am not able to show any data on the homescreen nor sending anything over mqtt, this is the code as I have it now: `` import string import mqtt

    class ESMR

    var serialport

    def init()
        # gpio_rx:4 gpio_tx:5
        self.serialport = serial(4, 5, 115200, serial.SERIAL_8N1)
        mqtt.subscribe("your_subscribe_topic_here", self.process_esmr)
        print("ESMR initialized")
    end

    def process_esmr(topic, idx, payload_s, payload_b)
        print("Received MQTT message")
        var serline = payload_s

        var electricity_kw_using, electricity_kw_providing
        var electricity_kwh_used_1, electricity_kwh_used_2
        var electricity_kwh_provided_1, electricity_kwh_provided_2
        var electricity_voltage_l1, electricity_voltage_l2, electricity_voltage_l3
        var electricity_current_l1, electricity_current_l2, electricity_current_l3
        var electricity_kw_using_l1, electricity_kw_using_l2, electricity_kw_using_l3
        var electricity_kw_providing_l1, electricity_kw_providing_l2, electricity_kw_providing_l3
        var gas_m3, gas_datetime

        var value = string.split(serline,"(")[1]
        value = string.split(value,")")[0]
        value = string.split(value,"*")[0]
        var value2 = string.split(serline,"(")[2]
        value2 = string.split(value2,"*")[0]

        print("Parsing values from received message")
        if (string.count(serline, "1-0:1.8.1") == 1) electricity_kwh_used_1 = number(value)
        if (string.count(serline, "1-0:2.8.1") == 1) electricity_kwh_provided_1 = number(value)
        if (string.count(serline, "1-0:1.8.2") == 1) electricity_kwh_used_2 = number(value)
        if (string.count(serline, "1-0:2.8.1") == 1) electricity_kwh_provided_1 = number(value)
        if (string.count(serline, "1-0:2.8.2") == 1) electricity_kwh_provided_2 = number(value)

        if (string.count(serline, "1-0:1.7.0") == 1) electricity_kw_using = number(value)
        if (string.count(serline, "1-0:2.7.0") == 1) electricity_kw_providing = number(value)

        if (string.count(serline, "1-0:21.7.0") == 1) electricity_kw_using_l1 = number(value)
        if (string.count(serline, "1-0:41.7.0") == 1) electricity_kw_using_l2 = number(value)
        if (string.count(serline, "1-0:61.7.0") == 1) electricity_kw_using_l3 = number(value)

        if (string.count(serline, "1-0:22.7.0") == 1) electricity_kw_providing_l1 = number(value)
        if (string.count(serline, "1-0:42.7.0") == 1) electricity_kw_providing_l2 = number(value)
        if (string.count(serline, "1-0:62.7.0") == 1) electricity_kw_providing_l3 = number(value)

        if (string.count(serline, "1-0:32.7.0") == 1) electricity_voltage_l1 = number(value)
        if (string.count(serline, "1-0:52.7.0") == 1) electricity_voltage_l2 = number(value)
        if (string.count(serline, "1-0:72.7.0") == 1) electricity_voltage_l3 = number(value)

        if (string.count(serline, "1-0:31.7.0") == 1) electricity_current_l1 = number(value)
        if (string.count(serline, "1-0:51.7.0") == 1) electricity_current_l2 = number(value)
        if (string.count(serline, "1-0:71.7.0") == 1) electricity_current_l3 = number(value)

        if (string.count(serline, "0-1:24.2.1") == 1) gas_datetime = value
        if (string.count(serline, "0-1:24.2.1") == 1) gas_m3 = number(value2)

        # Publish the parsed data through MQTT
        print("Publishing parsed data through MQTT")
        mqtt.publish("test", generate_output_msg(electricity_kwh_used_1, electricity_kwh_used_2, electricity_kwh_provided_1, electricity_kwh_provided_2, electricity_kw_using, electricity_kw_using_l1, electricity_kw_using_l2, electricity_kw_using_l3, electricity_kw_providing, electricity_kw_providing_l1, electricity_kw_providing_l2, electricity_kw_providing_l3, electricity_voltage_l1, electricity_voltage_l2, electricity_voltage_l3, electricity_current_l1, electricity_current_l2, electricity_current_l3, gas_m3, gas_datetime))
    end

    def generate_output_msg(electricity_kwh_used_1, electricity_kwh_used_2, electricity_kwh_provided_1, electricity_kwh_provided_2, electricity_kw_using, electricity_kw_using_l1, electricity_kw_using_l2, electricity_kw_using_l3, electricity_kw_providing, electricity_kw_providing_l1, electricity_kw_providing_l2, electricity_kw_providing_l3, electricity_voltage_l1, electricity_voltage_l2, electricity_voltage_l3, electricity_current_l1, electricity_current_l2, electricity_current_l3, gas_m3, gas_datetime)
        return string.format(
            "{s}electricity used 1{m}%.3f kWh{e}"..
            "{s}electricity used 2{m}%.3f kWh{e}"..
            "{s}electricity provided 1{m}%.3f kWh{e}"..
            "{s}electricity provided 2{m}%.3f kWh{e}"..
            "{s}electricity using{m}%.3f kW{e}"..
            "{s}electricity using L1{m}%.3f kW{e}"..
            "{s}electricity using L2{m}%.3f kW{e}"..
            "{s}electricity using L3{m}%.3f kW{e}"..
            "{s}electricity providing{m}%.3f kW{e}"..
            "{s}electricity providing L1{m}%.3f kW{e}"..
            "{s}electricity providing L2{m}%.3f kW{e}"..
            "{s}electricity providing L3{m}%.3f kW{e}"..
            "{s}electricity voltage L1{m}%.3f V{e}"..
            "{s}electricity voltage L2{m}%.3f V{e}"..
            "{s}electricity voltage L3{m}%.3f V{e}"..
            "{s}electricity current L1{m}%.3f A{e}"..
            "{s}electricity current L2{m}%.3f A{e}"..
            "{s}electricity current L3{m}%.3f A{e}"..
            "{s}gas{m}%.3f m3{e}"..
            "{s}gas datetime{m}%s{e}",
            electricity_kwh_used_1, electricity_kwh_used_2,
            electricity_kwh_provided_1, electricity_kwh_provided_2,
            electricity_kw_using, electricity_kw_using_l1, electricity_kw_using_l2, electricity_kw_using_l3,
            electricity_kw_providing, electricity_kw_providing_l1, electricity_kw_providing_l2, electricity_kw_providing_l3,
            electricity_voltage_l1, electricity_voltage_l2, electricity_voltage_l3,
            electricity_current_l1, electricity_current_l2, electricity_current_l3,
            gas_m3, gas_datetime)
    end

    def read_esmr()
        var sermsg, serline

        if (self.serialport.available() > 0)
            sermsg += self.serialport.read().asstring()
            var lastlineendpos = 0
            var serialline = ""
            for i:0..size(sermsg)-1
                if ((sermsg[i] == 10) || (sermsg[i] == 13))
                    if (serialline != "")
                        print("Processing received line")
                        self.process_esmr("data", 0, serialline, bytes())
                    serialline = ""
                    lastlineendpos = i
                else
                    serialline += sermsg[i]
            end
            if (i > 0)
                sermsg = string.split(sermsg, i)[1]
            end
        end
    end

    #- trigger a read every second -#
    def every_50ms()
        read_esmr()
    end
end
var esmr = ESMR()
tasmota.add_driver(esmr)
print("ESMR driver added")

``

when loading the very script is also down print anything so I don't know where it goes wrong

jeroenst commented 1 month ago

You can try debugging with adding print commands.

I also miss the tasmota.web_send_decimal command in your script for adding the values to the main webpage.

tasmota.web_send_decimal    (message:string) -> nil
Adds an HTML fragment to the Web output, similar to web_send but converts decimal dot . to the locale decimal separator.
Can be called only in web_sensor() method of a registered driver (see cookbook). It is called at each main page refresh.

https://tasmota.github.io/docs/Berry/#tasmota-object

https://tasmota.github.io/docs/Berry-Cookbook/#step-by-step-approach (step 6)

mediaessenz commented 1 month ago

There are several missing end commands in the read_esmr function. Imo this function is not working at all, also after adding the missing end commands. Additional there are some missing self. e.g. the read_esmr() call inside the every_50ms function should be self.read_esmr().

mediaessenz commented 1 month ago

I build something similar for a heater, based on this code, which works for me:

#-
 - Read serial data from hargassner heater and report some data to a MQTT broker
 -#

class hargassner

    var serialport
    var serialmsg
    var kessel_ist, kessel_soll
    var vorlauf_ist, vorlauf_soll
    var aussen_mittel, aussen_gemessen
    var rauchgas
    var co2
    var boiler

    def init()
        self.kessel_ist = 0
        self.kessel_soll = 0
        self.vorlauf_ist = 0
        self.vorlauf_soll = 0
        self.aussen_mittel = 0
        self.aussen_gemessen = 0
        self.rauchgas = 0
        self.boiler = 0
        self.co2 = 0
        # gpio_rx:20 gpio_tx:21
        self.serialport = serial(20, 21, 19200, serial.SERIAL_8N1)
        self.serialmsg = ""
    end

    def process_esmr(line)
        import string
        print("Processing ...")
        print(line)
        if string.count(line, "pm", 0, 2) == 1
            print("Found Datapackage")
            print(line)
            var dataList = string.split(string.split(line, "pm ")[1], " ")
            print(str(dataList))
            self.kessel_ist = number(dataList[2])
            self.kessel_soll = number(dataList[13])
            self.vorlauf_ist = number(dataList[6])
            self.vorlauf_ist = number(dataList[8])
            self.aussen_mittel = number(dataList[4])
            self.aussen_gemessen = number(dataList[5])
            self.rauchgas = number(dataList[3])
            self.boiler = number(dataList[10])
            self.co2 = number(dataList[1])
        end
    end

    def read_esmr()
        print("Function read_esmr called")
        import string
        if (self.serialport.available() > 0)
            var lastlineendpos = 0
            var serialline = ""
            self.serialmsg += self.serialport.read().asstring()
            for i:0..size(self.serialmsg)-1
                if ((self.serialmsg[i] == string.char(10)) || (self.serialmsg[i] == string.char(13)))
                    if (serialline != "")
                        self.process_esmr(serialline)
                    end
                    serialline = ""
                    lastlineendpos = i
                else
                    serialline += self.serialmsg[i]
                end
            end
            if (lastlineendpos > 0) 
                self.serialmsg = string.split(self.serialmsg, lastlineendpos)[1] 
            end
        end
    end

    #- trigger a read every second -#
    def every_second()
        self.read_esmr()
    end

    #- display sensor value in the web UI -#
    def web_sensor()
        import string
        tasmota.web_send_decimal(string.format(
            "{s}Kesseltemperatur (ist){m}%.2f°C{e}"..
            "{s}Kesseltemperatur (soll) {m}%.2f°C{e}"..
            "{s}Vorlauftemperatur (ist){m}%.2f°C{e}"..
            "{s}Vorlauftemperatur (soll){m}%.2f°C{e}"..
            "{s}Aussentemperatur (mittel){m}%.2f°C{e}"..
            "{s}Aussentemperatur (gemessen){m}%.2f°C{e}"..
            "{s}Rauchgastemperatur {m}%.2f°C{e}"..
            "{s}Boilertemperatur {m}%.2f°C{e}"..
            "{s}CO2{m}%.2f{e}",
            self.kessel_ist, self.kessel_soll, self.vorlauf_ist, self.vorlauf_soll, self.aussen_mittel, self.aussen_gemessen, self.rauchgas, self.boiler, self.co2)
        )
    end

    #- add sensor value to teleperiod -#
    def json_append()
        import string
        tasmota.response_append(string.format(
            ",\"HARGASSNER\":{\"KesselIst\":%.2f,\"KesselSoll\":%.2f,\"VorlaufIst\":%.2f,"..
            "\"VorlaufSoll\":%.2f,\"AussenMittel\":%.2f,\"AussenGemessen\":%.2f,\"Rauchgas\":%.2f,"..
            "\"Boiler\":%.2f,\"CO2\":%.2f}",
            self.kessel_ist, self.kessel_soll, self.vorlauf_ist, self.vorlauf_soll, self.aussen_mittel, self.aussen_gemessen, self.rauchgas, self.boiler, self.co2)
        )
    end
end

var hargassner_sm = hargassner()
tasmota.add_driver(hargassner_sm)
mediaessenz commented 1 month ago

The MQTT message sending is currently not working in my setup, but this will be the next step.

georgewahba commented 1 month ago

ik heb deze informatie gekregen van de maker van de p1 meter, kan eventueel helpen: CleanShot 2024-05-21 at 11 46 31@2x CleanShot 2024-05-21 at 11 47 03@2x

georgewahba commented 1 month ago

I got it almost to work with this code, it prints out on the web ui and it sends trough mqtt only thing not working yet is that it doesn't display any values

`class ESMR var serialport var electricity_kw_using, electricity_kw_providing var electricity_kwh_used_1, electricity_kwh_used_2 var electricity_kwh_provided_1, electricity_kwh_provided_2 var electricity_voltage_l1, electricity_voltage_l2, electricity_voltage_l3 var electricity_current_l1, electricity_current_l2, electricity_current_l3 var electricity_kw_using_l1, electricity_kw_using_l2, electricity_kw_using_l3 var electricity_kw_providing_l1, electricity_kw_providing_l2, electricity_kw_providing_l3 var gas_m3, gas_datetime var serialmsg

def init()
    # Initialize the serial port with gpio_rx:10 gpio_tx:-1/21
    self.serialport = serial(10, -1, 115200, serial.SERIAL_8N1)
    self.serialmsg = ""
end

def process_emsr(serline)
    # Extracting values from the serial line
    import string
    var parts = string.split(serline, "(")
    if size(parts) < 2
        return
    end
    var value = string.split(parts[1], ")")[0]
    value = string.split(value, "*")[0]
    var value2 = ""
    if size(parts) > 2
        value2 = string.split(parts[2], "*")[0]
    end

    # Parsing different types of values based on identifiers
    if string.count(serline, "1-0:1.8.1") == 1
        self.electricity_kwh_used_1 = number(value)
    end
    if string.count(serline, "1-0:1.8.2") == 1
        self.electricity_kwh_used_2 = number(value)
    end
    if string.count(serline, "1-0:2.8.1") == 1
        self.electricity_kwh_provided_1 = number(value)
    end
    if string.count(serline, "1-0:2.8.2") == 1
        self.electricity_kwh_provided_2 = number(value)
    end

    if string.count(serline, "1-0:1.7.0") == 1
        self.electricity_kw_using = number(value)
    end
    if string.count(serline, "1-0:2.7.0") == 1
        self.electricity_kw_providing = number(value)
    end

    if string.count(serline, "1-0:21.7.0") == 1
        self.electricity_kw_using_l1 = number(value)
    end
    if string.count(serline, "1-0:41.7.0") == 1
        self.electricity_kw_using_l2 = number(value)
    end
    if string.count(serline, "1-0:61.7.0") == 1
        self.electricity_kw_using_l3 = number(value)
    end

    if string.count(serline, "1-0:22.7.0") == 1
        self.electricity_kw_providing_l1 = number(value)
    end
    if string.count(serline, "1-0:42.7.0") == 1
        self.electricity_kw_providing_l2 = number(value)
    end
    if string.count(serline, "1-0:62.7.0") == 1
        self.electricity_kw_providing_l3 = number(value)
    end

    if string.count(serline, "1-0:32.7.0") == 1
        self.electricity_voltage_l1 = number(value)
    end
    if string.count(serline, "1-0:52.7.0") == 1
        self.electricity_voltage_l2 = number(value)
    end
    if string.count(serline, "1-0:72.7.0") == 1
        self.electricity_voltage_l3 = number(value)
    end

    if string.count(serline, "1-0:31.7.0") == 1
        self.electricity_current_l1 = number(value)
    end
    if string.count(serline, "1-0:51.7.0") == 1
        self.electricity_current_l2 = number(value)
    end
    if string.count(serline, "1-0:71.7.0") == 1
        self.electricity_current_l3 = number(value)
    end

    if string.count(serline, "0-1:24.2.1") == 1
        self.gas_datetime = value
        self.gas_m3 = number(value2)
    end
end

def read_esmr()
    import string
    var sermsg = self.serialmsg

    if self.serialport.available() > 0
        sermsg += self.serialport.read().asstring()
        var lastlineendpos = 0
        var serialline = ""
        var i = 0
        while i < size(sermsg)
            if sermsg[i] == 10 || sermsg[i] == 13
                if serialline != ""
                    print("Processing received line")
                    self.process_emsr(serialline)
                end
                serialline = ""
                lastlineendpos = i
            else
                serialline += sermsg[i]
            end
            i += 1
        end

        if lastlineendpos > 0
            self.serialmsg = string.split(sermsg, lastlineendpos + 1)[1]
        end
    end
end

# Trigger a read every 50ms
def every_50ms()
    self.read_esmr()
end

# Display sensor value in the web UI
def web_sensor()
    import string
    var msg = string.format(
        "{s}electricity used 1{m}%.3f kWh{e}"..
        "{s}electricity used 2{m}%.3f kWh{e}"..
        "{s}electricity provided 1{m}%.3f kWh{e}"..
        "{s}electricity provided 2{m}%.3f kWh{e}"..
        "{s}electricity using{m}%.3f kW{e}"..
        "{s}electricity using L1{m}%.3f kW{e}"..
        "{s}electricity using L2{m}%.3f kW{e}"..
        "{s}electricity using L3{m}%.3f kW{e}"..
        "{s}electricity providing{m}%.3f kW{e}"..
        "{s}electricity providing L1{m}%.3f kW{e}"..
        "{s}electricity providing L2{m}%.3f kW{e}"..
        "{s}electricity providing L3{m}%.3f kW{e}"..
        "{s}electricity voltage L1{m}%.3f V{e}"..
        "{s}electricity voltage L2{m}%.3f V{e}"..
        "{s}electricity voltage L3{m}%.3f V{e}"..
        "{s}electricity current L1{m}%.3f A{e}"..
        "{s}electricity current L2{m}%.3f A{e}"..
        "{s}electricity current L3{m}%.3f A{e}"..
        "{s}gas{m}%.3f m3{e}"..
        "{s}gas datetime{m}%s{e}",
        self.electricity_kwh_used_1, self.electricity_kwh_used_2, 
        self.electricity_kwh_provided_1, self.electricity_kwh_provided_2, 
        self.electricity_kw_using, self.electricity_kw_using_l1, self.electricity_kw_using_l2, self.electricity_kw_using_l3, 
        self.electricity_kw_providing, self.electricity_kw_providing_l1, self.electricity_kw_providing_l2, self.electricity_kw_providing_l3, 
        self.electricity_voltage_l1, self.electricity_voltage_l2, self.electricity_voltage_l3,
        self.electricity_current_l1, self.electricity_current_l2, self.electricity_current_l3, 
        self.gas_m3, self.gas_datetime)
    tasmota.web_send_decimal(msg)
end

# Add sensor value to teleperiod
def json_append()
    import string
    var msg = string.format(
        ",\"ESMR\":{\"EU1\":%.3f,\"EU2\":%.3f,\"EP1\":%.3f,\"EP2\":%.3f,"..
        "\"EU\":%.3f,\"EUL1\":%.3f,\"EUL2\":%.3f,\"EUL3\":%.3f,"..
        "\"EP\":%.3f,\"EPL1\":%.3f,\"EPL2\":%.3f,\"EPL3\":%.3f,"..
        "\"EVL1\":%.3f,\"EVL2\":%.3f,\"EVL3\":%.3f,"..
        "\"ECL1\":%.3f,\"ECL2\":%.3f,\"ECL3\":%.3f,"..
        "\"G\":%.3f,\"GDT\":\"%s\"}",
        self.electricity_kwh_used_1, self.electricity_kwh_used_2, 
        self.electricity_kwh_provided_1, self.electricity_kwh_provided_2, 
        self.electricity_kw_using, self.electricity_kw_using_l1, self.electricity_kw_using_l2, self.electricity_kw_using_l3, 
        self.electricity_kw_providing, self.electricity_kw_providing_l1, self.electricity_kw_providing_l2, self.electricity_kw_providing_l3, 
        self.electricity_voltage_l1, self.electricity_voltage_l2, self.electricity_voltage_l3,
        self.electricity_current_l1, self.electricity_current_l2, self.electricity_current_l3, 
        self.gas_m3, self.gas_datetime)
    tasmota.response_append(msg)
end

end

var esmr = ESMR() tasmota.add_driver(esmr)`

jeroenst commented 1 month ago

Thank you for all the work you did already. At the moment I have very little spare time to help out, but as soon you have things working, I will test your code and create a new commit.

jeroenst commented 1 month ago

I think you have to add self. web_sensor() and self.json_append() in the if statement of gas (because afaik that's the last dsmr value received):

if string.count(serline, "0-1:24.2.1") == 1
    self.gas_datetime = value
    self.gas_m3 = number(value2)
    self.web_sensor();
    self.json_append();
end