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)
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.
And the final result in the webpage of the Domotics:
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)
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.
And the final result in the webpage of the Domotics:
B4X:
#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(6) As 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(115200, 12, 13)
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