B4R Code Snippet reading smart meter smr5.0 p1 port

Discussion in 'B4R Code Snippets' started by MbedAndroid, Apr 21, 2019.

  1. MbedAndroid

    MbedAndroid Active Member Licensed User

    We should have all a smart meter, so such a beast is installed here in home. The smartmeter provides via a so called P1 port a detailed report from Electricity, gas, and sometimes water. Even the solarenergy is reported in the telegram.
    For details about the telegram read https://www.netbeheernederland.nl/_upload/Files/Slimme_meter_15_a727fce1f1.pdf

    The smr5.0 is one of many installed meters, but lucky there is documentation and the code can be changed easily.
    With B4R I made a adapter which receives, decodes and transmits the data through Wifi to my home Domotica system running with java build with B4J

    Using a WeMos mini D1 a small box is needed. Power is supplied via the P1 port. No adapters are needed. All packed in a small box
    schematic : http://www.esp8266thingies.nl/wp/wp-content/uploads/2016/11/Screen-Shot-2017-01-03-at-16.43.23.png
    Only i use different pins. The serial input is tied to P12 via serial software. Hardware serialport didnt work. (serial port 2)

    [​IMG]

    In my case no watermeter is connected so i installed a flowmeter which gives pulses for every drop of water. No calibration how many pulses, but i found that 256 pulses is equivalent for aprox 1 liter of water.
    We dont need a report of every CC, so the unit transmits only the liters.[​IMG]

    And the final result in the webpage of the Domotics:
    upload_2019-4-21_18-1-40.png

    Code:
    #Region Project Attributes
       
    #AutoFlushLogs: True
       
    #CheckArrayBounds: True
       
    #StackBufferSize: 900
    #End Region
    '1-0:1.8.1(003808.351*kWh)
    '1-0:1.8.2(002948.827*kWh)
    '1-0:2.8.1(001285.951*kWh)
    '1-0:2.8.2(002876.514*kWh)
    '1-0:1.7.0(01.193*kW)
    '1-0:2.7.0(00.000*kW)
    '1-0:1.7Actual electricity powerdelivered (+P)in 1 Wattreso
    '1-0:2.7.0.255Actual electricity Power received (-P) in 1 Wattresolution
    '0-0:1.0.0(101209113020W time
    '0-1:24.2.1(101209112500W)(12785.123*m3
    '-0:96.14.0(0002)
    'Serial0 - RX: GPIO3 , TX: GPIO1
    'Serial1 - RX: GPIO9 , TX: GPIO10
    'Serial2 - RX: GPIO16 , TX: GPIO17


    Sub Process_Globals
       
    Type averageGas (timestamp As ULong, GasAtTime As Float)
       
    Public Serial1 As Serial
       
    Private SerialNative2 As Stream
       
    Private astream As AsyncStreams
       
    Private softserial As SoftwareSerial
       
    Private Timer1 As Timer
       
    Private Timer2 As Timer
    '   Private server As WiFiServerSocket
    '   Private serverport As UInt = 80
       Dim count=0 As Byte
       
    Private usocket As WiFiUDP
       
    Private wifi As ESP8266WiFi
       
    Dim firstpackage=False As Boolean
       
    #if test
       Private ip() As Byte = Array As Byte(192, 168, 1,64)
       #Else
       Private ip() As Byte = Array As Byte(192, 168, 1,22)
       
    #end if
       
    Private port As UInt = 5000
       
    Dim MacArray(6As Byte
       
    Private bc As ByteConverter
       
    Dim Pwa=1000 As Float
       
    Private d1pins As D1Pins
       
    Dim Pwt1 As Float
       
    Dim Pwt2 As Float
       
    Dim Pwtr1 As Float
       
    Dim Pwtr2 As Float
       
    Dim Pwa As Float
       
    Dim Pwar As Float
       
    Dim Gast As Float
       
    Dim GasAverage As Float
       
    Dim Water=0 As Float
       
    Dim OneLiterBucket=0 As UInt
       
    Dim WateraverageCount=0 As ULong
       
    Dim WaterFlow=0 As ULong
       
    Dim tarif As Int
       
    Private HallSensor As Pin
       
    Private P1Data As Pin
       
    Private Flowsensor As Pin
       
    Dim avg As averageGas
    End Sub

    Private Sub AppStart
       Serial1.Initialize(
    115200)
        
    Log("AppStart")
       RunNative(
    "SerialNative2"Null)
       HallSensor.Initialize(d1pins.D0,HallSensor.MODE_INPUT_PULLUP)
       HallSensor.AddListener(
    "Change_state")
       P1Data.Initialize(d1pins.D1,P1Data.MODE_OUTPUT)
       Flowsensor.Initialize(d1pins.D2,Flowsensor.MODE_OUTPUT)
       P1Data.DigitalWrite(
    True)
       Flowsensor.DigitalWrite(
    True)
     
       astream.Initialize(SerialNative2, 
    "astream_NewData""astream_Error")
       softserial.Initialize(
    1152001213)
       astream.Initialize(softserial.Stream, 
    "astream_newdata"Null)
       usocket.Initialize(
    5000,"usocket_PacketArrived")
       
    If wifi.Connect2("Sid","password"Then 'change to your network SSID (use Connect2 if a password is required).
           Log("Connected to wireless network.")
           
    Log("My ip: ", wifi.LocalIp)
       
    Else
           
    Log("Failed to connect.")
           
    Return
           
    End If
    #if test
       Timer1.Initialize("Timer1_Tick", 1000) ''sample every 1 minutes for average
       Timer1.Enabled = True
    #end if

       Timer2.Initialize(
    "Timer2_Tick"10)
       Timer2.Enabled = 
    True

    End Sub

    Sub Timer2_Tick
       WateraverageCount=WateraverageCount+
    1
       
    If WateraverageCount>60000 Then 'wait for 10 minutes before resetting the counter
           Water=0
       
    End If

    End Sub

    Sub Change_state (State As Boolean)
       
    Select State
           
    Case True
               WaterFlow=WaterFlow+
    1           'accumulate counts just to 1 liter to send it up
               If WaterFlow>255 Then
                                       WaterFlow=
    0
                                       OneLiterBucket=OneLiterBucket+
    1 'increase 1 liter and send it for the next frame
               End If
               
    If WateraverageCount>0 Then
                                       Water=
    1200/WateraverageCount 'will give aprox liters/hour
                                       Else
                                           Water=
    0
                                       
    End If
               WateraverageCount=
    0
               Flowsensor.DigitalWrite(
    False)
    #if test
               Log("state: Detected")
    #end if
           
    Case False
               Flowsensor.DigitalWrite(
    True)
    #if test
               Log("state: Not Detected")
    #end if
       
    End Select
    End Sub

    Sub astream_Terminated
       
    Log("Connection is broken.")

    End Sub
    Sub astream_Error

    End Sub
    Sub astream_NewData (s() As Byte)
       
    ''Log(s)
       Dim temp As Float
     
       temp=bc.StringFromBytes(Parsing(s,
    "1-0:1.8.1"))
       
    If temp<>-1 Then
                           Pwt1=temp
                           P1Data.DigitalWrite(
    False)
       
    End If
       temp=bc.StringFromBytes(Parsing(s,
    "1-0:1.8.2"))
       
    If temp<>-1 Then Pwt2=temp
       temp=bc.StringFromBytes(Parsing(s,
    "1-0:2.8.1"))
       
    If temp<>-1 Then Pwtr1=temp
       temp=bc.StringFromBytes(Parsing(s,
    "1-0:2.8.2"))
       
    If temp<>-1 Then
                           Pwtr2=temp
                           P1Data.DigitalWrite(
    True)
       
    End If
    '   1-0:1.7.0(00.000*kW)
       temp=bc.StringFromBytes(Parsing(s,"1-0:1.7.0"))
       
    If temp<>-1 Then Pwa=temp
       temp=bc.StringFromBytes(Parsing(s,
    "1-0:2.7.0"))
       
    If temp<>-1 Then Pwar=temp
       temp=(bc.StringFromBytes(Parsing(s,
    "0:96.14.0")))
       
    If temp<>-1 Then tarif=temp
       
    Dim sg()  As Byte
       sg=(Parsing(s,
    "0-1:24.2.1"))
       
    If sg<>"-1" Then
           
    Dim start As Int =bc.IndexOf(sg,"(")
           
    If start<>-1 Then
                       
    Dim time=(((sg(6)-48)*10+(sg(7)-48))*60+(sg(8)-48)*10+(sg(9)-48))*60+(sg(10)-48)*10+sg(11)-48 As ULong
                       
    If time>86400 Then time=0 'error condition, cant be > then 86400
                       count=count+1
                       Gast=bc.StringFromBytes(bc.SubString(sg,start+
    1))
                       
    End If
           
    If count=6 Then
             
               count=
    0 
               
    Dim deltaT= time-avg.timestamp As ULong
               avg.timestamp=time 
    'save new timestamp
               Dim deltaG=Gast-avg.GasAtTime As Float
               avg.GasAtTime=Gast
               
    If deltaG>0 And firstpackage Then
                                   GasAverage=deltaG*
    3600/deltaT
                               
    Else
                                   GasAverage=
    0
                                   firstpackage=
    True
                           
    End If
               
    Dim buffer As String=JoinStrings(Array As String(wifi.LocalIp ,",","P1",",",bc.HexFromBytes(MacAddress),",",NumberFormat(Pwt1,1,1),",",NumberFormat(Pwt2,1,1),",",NumberFormat(Pwtr1,1,1),",",NumberFormat(Pwtr2,1,1),",",NumberFormat(Pwa,1,3),",",NumberFormat(Pwar,1,3),",",NumberFormat(Gast,1,3),",",NumberFormat(tarif,1,0),",",NumberFormat(GasAverage,1,3),",",NumberFormat(Water,1,3),",",NumberFormat(OneLiterBucket,1,0)))
               OneLiterBucket=
    0
               usocket.BeginPacket(ip, port)
               usocket.Write(buffer)
               usocket.SendPacket
    #if test
               Log("packed send")
               Log(Pwt1)
               Log(Pwt2)
               Log(Pwtr1)
               Log(Pwtr2)
               Log(Pwa)
               Log(Pwar)
               Log(Gast)
               Log(tarif)
               Log(GasAverage)
               Log(Water)
    #end if
               Pwa=-
    1
               Pwar=-
    1
           
    End If
       
    End If



    End Sub
    Sub Parsing(s() As Byte,search() As Byte) As  Byte()
       
    If bc.StartsWith(s,search)  Then
    '       Dim index=bc.IndexOf(s,search) As Byte
           Dim start As Int =bc.IndexOf(s,"(")
           
    Dim stop As Int =bc.IndexOf(s,"*kW")
           
    Dim closingparenthesis As Int =bc.IndexOf(s,")")
           
    Dim gas As Int =bc.IndexOf(s,"*m3)")

    'detect electricity lines
           If  stop<>-1 And start<>-1 Then
           
    Return (bc.SubString2(s,start+1,stop))
           
    Else

    'detect gas lines
           If gas<>-1 And start<>-1 Then
                   
    Return (bc.SubString2(s,start+1,gas))
               
    Else
       
    'Detect all other lines     
               If closingparenthesis<>-1 And start<>-1 Then
                   
    Return (bc.SubString2(s,start+1,closingparenthesis))
                   
    Else
                       
    Return "-1"
               
    End If
           
    End If
           
    End If 
           
    Else
               
    Return "-1"
       
    End If

    End Sub
    #if test
    Private Sub Timer1_Tick
    Select  count
           Case 0:       Dim s() As Byte ="0-1:24.2.1(101209112500W)(12785.123*m3)"
           Case 1:       Dim s() As Byte ="0-1:24.2.1(101209113000W)(12786.123*m3)"
           Case 2:       Dim s() As Byte ="0-1:24.2.1(101209113500W)(12787.123*m3)"
           Case 3:       Dim s() As Byte ="0-1:24.2.1(101209114500W)(12789.123*m3)"
           Case 4:       Dim s() As Byte ="0-1:24.2.1(101209120500W)(12790.123*m3)"
           Case 5:       Dim s() As Byte ="0-1:24.2.1(101209134500W)(12791.123*m3)"
    End Select
    Dim sg()=(Parsing(s,"0-1:24.2.1")) As Byte
    Log(sg)
    If sg<>"-1" Then
       Dim start As Int =bc.IndexOf(sg,"(")
       If start<>-1 Then
    '           Log(sg(6))
    '           Log(sg(7))
    '           Log(sg(8))
    '           Log(sg(9))
    '           Log(sg(10))
    '           Log(sg(11))
             
           Dim time=(((sg(6)-48)*10+(sg(7)-48))*60+(sg(8)-48)*10+(sg(9)-48))*60+(sg(10)-48)*10+sg(11)-48 As ULong
           If time>86400 Then time=0 'error condition, cant be > then 86400
           Log (time)
           count=count+1
           Gast=bc.StringFromBytes(bc.SubString(sg,start+1))
       End If
           Log(Gast)
           Dim deltaT= time-avg.timestamp As ULong
           Log (deltaT)
           If deltaT<0 Then deltaT=deltaT+86399
           avg.timestamp=time 'save new timestamp
           Dim deltaG=Gast-avg.GasAtTime As Float
           avg.GasAtTime=Gast
           If deltaG>0 And firstpackage Then
               GasAverage=deltaG*3600/deltaT
               Log(GasAverage)
           Else
               GasAverage=0
               firstpackage=True
           End If
       If count=6 Then
       count=0
       Dim deltaT= time-avg.timestamp As ULong
       Log (deltaT)
       If deltaT<0 Then deltaT=deltaT+86399
       avg.timestamp=time 'save new timestamp
       Dim deltaG=Gast-avg.GasAtTime As Float
       avg.GasAtTime=Gast
           If deltaG>0 And firstpackage Then
           GasAverage=deltaG*3600/deltaT
           Log(GasAverage)
       Else
           GasAverage=0
           firstpackage=True
       End If
         
               Dim buffer As String=JoinStrings(Array As String(wifi.LocalIp ,",","P1",",",bc.HexFromBytes(MacAddress),",",NumberFormat(Pwt1,1,1),",",NumberFormat(Pwt2,1,1),",",NumberFormat(Pwtr1,1,1),",",NumberFormat(Pwtr2,1,1),",",NumberFormat(Pwa,1,3),",",NumberFormat(Pwar,1,3),",",NumberFormat(Gast,1,3),",",NumberFormat(tarif,1,0),",",NumberFormat(GasAverage,1,3),",",NumberFormat(Water,1,3),",",NumberFormat(OneLiterBucket,1,0)))
               OneLiterBucket=0
    '           Dim buffer As String=JoinStrings(Array As String(wifi.LocalIp ,",","P1",",",bc.HexFromBytes(MacAddress),",",NumberFormat(Pwt1,1,1),",",NumberFormat(Pwt2,1,1),",",NumberFormat(Pwtr1,1,1),",",NumberFormat(Pwtr2,1,1),",",NumberFormat(Pwa,1,3),",",NumberFormat(Pwar,1,3),",",NumberFormat(Gast,1,3),",",NumberFormat(tarif,1,0)))
               Log(buffer)
               usocket.BeginPacket(ip, port)
               usocket.Write(buffer)
               usocket.SendPacket
           End If

    End If
    End Sub
    #end if


    'Public Sub SendOutString(text As String)
    '
    '   Dim Buffer(6) As Byte
    '   For i = 0 To text.Length-1
    '       Buffer(i)=text.GetBytes(i)
    '   Next
    '   ''Log(Buffer)
    ''   Log("buffer send")
    '   astream.Write(Buffer)
    'End Sub
    Private Sub usocket_PacketArrived (Data() As Byte, ip1() As Byte, port1 As UInt)
       
    'not used
       Log("Packet arrived")
    End Sub

    Sub MacAddress() As Byte()
       RunNative(
    "getMac"Null)
       
    Return MacArray
    End Sub


    #if C
      #include <ESP8266WiFi.h>
      void getMac(B4R::Object* u) {
      WiFi.macAddress((Byte*)b4r_main::_macarray->data);
    }
    #end if
    #if C
    HardwareSerial Serial2(2); // Second Hardware Port


    void SerialNative2(B4R::Object* unused)
    {
    ::Serial2.begin(115200);
    b4r_main::_serialnative2->wrappedStream = &::Serial2;
    }
    #End If
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice