OpenHab
So, the first attempt to collect statistics from the counter was made using the external cloud service ThingSpeak. A thin client (mini-computer) with a Ubuntu Server installed on the USB flash drive was used as the local server that polled the counter. This was the first mistake – a flash drive “died” in 3 months (an accident, I thought). Without making any conclusions, I killed the second flash drive in 2 months (regularity). In the third version, a usb pocket with a 2.5 “screw was already used as a storage.
ThingSpeak service itself allows some processing, but does not provide sufficient flexibility with data manipulation. Data for the day, for example, was collected as a sum If some data packet was not sent to the server or if I sent several data during the testing, an error occurred.The thought that it would be necessary to carry out two-rate accounting with time-based binding was not added to optimism.
In general, I decided to master OpenHab .
Problem one: get raw data from the counter.
The installation of the OpenHab itself is described in detail in the instructions. After installing, you need to install the Paper UI -> Bindings install ModBus binding – binding-modbus1 – 1.9.0
The ModBus bus is polled via USB-RS485 Adapter, so you need to make sure that the adapter is in the system, and add the user to openhab the right to access the port:
lsusb
Bus 002 Device 002: ID 0403: 6001 Future Technology Devices International, Ltd. FT232 Serial (UART) IC
Ls / dev / ttyUSB *
/ Dev / ttyUSB0
Sudo adduser openhab dialout
Sudo adduser openhab tty
Then it is recommended to configure the permissions for Java (this is also described in detail in the OpenHab installation instructions):
sudo vi / etc / default / openhab2
EXTRA_JAVA_OPTS = "- Dgnu.io.rxtx.SerialPorts = / dev / ttyUSB0"
After these manipulations, you need to configure the configuration file services / modbus.cfg :
sudo vi /etc/openhab2/services/modbus.cfg
# The period of the interrogation of the counter
Poll = 30000
# The counter does not allow you to subtract all the registers in one call, so you need to create a separate entry for each register. The start field is the register number. In the connection line, specify the port number and parameters (9600.8, n, 1), the delay before reading each register, and the response timeout.
# Voltage - 0x00
Serial.slave1.connection = / dev / ttyUSB0: 9600: 8: none: 1: rtu: 2000: 1000: none: none
Serial.slave1.type = input
Serial.slave1.start = 0
Serial.slave1.length = 2
Serial.slave1.valuetype = float32
# Current - 0x06
Serial.slave2.connection = / dev / ttyUSB0: 9600: 8: none: 1: rtu: 2000: 1000: none: none
Serial.slave2.type = input
Serial.slave2.start = 6
Serial.slave2.length = 2
Serial.slave2.valuetype = float32
# Active power - 0x0C
Serial.slave3.connection = / dev / ttyUSB0: 9600: 8: none: 1: rtu: 2000: 1000: none: none
Serial.slave3.type = input
Serial.slave3.start = 12
Serial.slave3.length = 2
Serial.slave3.valuetype = float32
# Meter reading (active energy) - 0x156
Serial.slave4.connection = / dev / ttyUSB0: 9600: 8: none: 1: rtu: 2000: 1000: none: none
Serial.slave4.type = input
Serial.slave4.start = 342
Serial.slave4.length = 2
Serial.slave4.valuetype = float32
Then you need to create the data items in the file items / sdm220.items :
sudo vi /etc/openhab2/items/sdm220.items
# Define the group for the elements
Group gSDM220
# And indicate where to get them and how to display them, energy is the name of the icon from the standard set
Number sdm220_voltage "Voltage [%.1f В]" (gSDM220) {modbus = "slave1: 0"}
Number sdm220_current "Current [%.2f А]" (gSDM220) {modbus = "slave2: 0"}
Number sdm220_actpower "Power [%.1f Вт]" (gSDM220) {modbus = "slave3: 0"}
Number sdm220_actcounter "Electricity meter [%.1f кВт*ч]" (gSDM220) {modbus = "slave4: 0"}
It remains to add the current readings to the dashboard. To do this, edit the file sitemaps / default.sitemap :
sudo vi /etc/openhab2/sitemaps/default.sitemap
Sitemap default label = "alk0v SmartHome (default sitemap)" {
Frame label = "Electric meter" {
Text item = sdm220_voltage
Text item = sdm220_current
Text item = sdm220_actpower
Text item = sdm220_actcounter
}
}
In principle, this is enough to see the current meter readings:
Task two: setting HabPanel and visualizing the readings
OpenHab supports several control panels. To me, the most liked the most HabPanel . Through Paper UI -> User Interfaces we establish HabPanel – ui-habpanel – 2.0.0 .
To draw graphs, you also need to store data somewhere. OpenHab uses the term Persistence for databases. I wanted to use the MySQL database, the community discussed many problems with this database, in the end I found an instruction that worked for me.
So, we install MySQL Persistence (persistence-mysql – 1.9.0).
Install MySQL
sudo apt-get install mysql-server
Sudo mysql -u root -p
Configuring the database
CREATE DATABASE OpenHAB;
CREATE USER 'openhab' @ 'localhost' IDENTIFIED BY 'YOURPASSWORD';
GRANT ALL PRIVILEGES ON OpenHAB. * TO 'openhab' @ 'localhost';
Quit
Restart openhab
sudo service openhab2 stop
Sudo service openhab2 start
Rule services / mysql.cfg :
# the database url like 'jdbc: mysql: // : / ' (without quotes)
Url = jdbc: mysql: // localhost: 3306 / openhab
# The database user
User = openhab
# The database password
Password = YOURPASSWORD
Rule persistence / mysql.persist . By default, the values of all Items will be entered into the database for each change:
Strategies {
// if no strategy is specified for an item entry below, the default list will be used
EveryMinute: "0 * * * *?"
Every5Minutes: "0 * / 5 * * *?"
EveryHour: "0 0 * * *?"
EveryDay: "0 0 0 * *?"
Default = everyChange
}
Items {
// persist all items once a day and on every change and restore them from the db at startup
*: Strategy = default, restoreOnStartup
}
If everything is configured correctly, the Items table and the ItemXX table for each Item should appear in the database.
Mysql> usage openhab;
The database changed
Mysql> show tables;
+ ------------------- +
| | | Tables_in_openhab |
+ ------------------- +
| | | Item1 |
| | | Item2 |
| | | Item3 |
| | | Item4 |
| | | Items |
+ ------------------- +
5 rows in set (0.00 sec)
Mysql> select * from Items;
+ -------- + -------------------------- +
| | | ItemId | ItemName |
+ -------- + -------------------------- +
| | | 1 | Sdm220_voltage |
| | | 2 | Sdm220_actpower |
| | | 3 | Sdm220_actcounter |
| | | 4 | Sdm220_current |
+ -------- + -------------------------- +
4 rows in set (0.00 sec)
Now you can create beauty in HabPanel.
Add Dashboard, add new widgets to it. To display the values, use the Dummy widget, to display the graphs – Chart . Everything is intuitive here. Parameters of power and voltage, I deduced one graph using two different Y scales.
Specify mysql as the data source:
Adjust the thresholds for the stress axis:
Adding Items, specify the color and type of the line for them, specify the Secondary axis for the voltage:
We get the result:)
]
The third task: hourly and daily accounting of spent electricity
Displaying the change of state in time is good, but I still want to get statistics of consumption for an hour, a day, a month. That is, the task is to periodically perform some calculations. Here the mechanism of rules in OpenHab comes to the aid.
So, set up Rules .
First you need to add new Items in items / sdm220.items :
Number sdm220_hourcounter (gSDM220)
Number sdm220_daycounter (gSDM220)
Then create the file rules / energy.rules in which you need to specify 2 rules: one will be executed once an hour, the second once a day.
rule "Energy by hour"
When
Time cron "0 0 * * *?"
Then
// calculate the flow. From the current meter readings, the values from the database are subtracted one hour earlier
Var hour = sdm220_actcounter.state as DecimalType - sdm220_actcounter.historicState (now.minusHours (1), "mysql" :). State as DecimalType
// output data to the debug log
LogInfo ("TEST", "sdm220_hourcounter =" + hour)
// assign the value of Item
PostUpdate (sdm220_hourcounter, hour)
End
Rule "Energy by day"
When
Time cron "0 0 0 * *?"
Then
Var day = sdm220_actcounter.state as DecimalType - sdm220_actcounter.historicState (now.minusDays (1), "mysql" :). State as DecimalType
PostUpdate (sdm220_daycounter, day)
For debugging, you can use the OpenHab console. Standard login and password: openhab / habopen. You can connect to it using the command:
ssh -p 8101 openhab @ localhost
Openhab> log: tail
19: 22: 00.012 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_hourcounter_day = 0.526123046875
19: 22: 00.014 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_daycounter = 10.861083984375
19: 22: 09.462 [INFO ] [marthome.event.ItemStateChangedEvent] - sdm220_current changed from 16.0433025360107421875 to 5.69449329376220703125
19: 22: 11.500 [INFO ] [marthome.event.ItemStateChangedEvent] - sdm220_actcounter changed from 2387.51904296875 to 2387.5458984375
19: 22: 13.532 [INFO ] [marthome.event.ItemStateChangedEvent] - sdm220_voltage changed from 192.7679595947265625 to 200.4195098876953125
19: 22: 15.568 [INFO ] [marthome.event.ItemStateChangedEvent] - sdm220_actpower changed from 2271.8486328125 to 1132.8717041015625
19: 23: 00.014 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_hourcounter_day = 0.515869140625
19: 23: 00.015 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_daycounter = 10.8769531250
Or you can view the log file:
tail -f /var/log/openhab2/openhab.log
2017-04-18 19: 17: 45.587 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'energy.rules'
2017-04-18 19: 18: 00.259 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_hourcounter_day = 0.571044921875
2017-04-18 19: 18: 00.272 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_daycounter = 10.8330078125
2017-04-18 19: 19: 00.015 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_daycounter = 10.83789062500
2017-04-18 19: 19: 00.025 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_hourcounter_day = 0.557861328125
2017-04-18 19: 20: 00.013 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_hourcounter_day = 0.55517578125
2017-04-18 19: 20: 00.024 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_daycounter = 10.859130859375
I plan to change the main electricity meter to a two-tariff meter, for which the electricity consumed in the range from 23:00 to 07:00 is paid with a coefficient of 0.5, so I would like to see the expected effect and carry out a two-rate accounting. First, I just added the additional conditions for time in the Items and Rules and put the day and night readings into two different tables. In the database everything was beautiful, but the graph looked clumsy, because the graph connected the last two values with a straight line:
To amuse your sense of beauty, it was necessary to get a little embarrassed.
So, The final rule script for two-rate accounting looks like this:
rule "Energy by hour"
When
Time cron "0 0 * * *?"
Then
Var hour = sdm220_actcounter.state as DecimalType - sdm220_actcounter.historicState (now.minusHours (1), "mysql" :). State as DecimalType
// define the time ranges
If (now.getHourOfDay> 7 && now.getHourOfDay <23)
{
LogInfo ("TEST", "sdm220_hourcounter_day =" + hour)
PostUpdate (sdm220_hourcounter_day, hour)
}
Else
{
// at the border of the ranges we add zero values to the graph
// since the timestamp is used as the primary key in the table, there is a one second pause between adding data to the same table
If (now.getHourOfDay == 7)
{
PostUpdate (sdm220_hourcounter_night, hour)
Thread :: sleep (1000)
PostUpdate (sdm220_hourcounter_night, 0)
Thread :: sleep (1000)
PostUpdate (sdm220_hourcounter_day, 0)
Thread :: sleep (1000)
PostUpdate (sdm220_hourcounter_day, hour)
}
Else if (now.getHourOfDay == 23)
{
PostUpdate (sdm220_hourcounter_day, hour)
Thread :: sleep (1000)
PostUpdate (sdm220_hourcounter_day, 0)
Thread :: sleep (1000)
PostUpdate (sdm220_hourcounter_night, 0)
Thread :: sleep (1000)
PostUpdate (sdm220_hourcounter_night, hour)
}
Else
{
PostUpdate (sdm220_hourcounter_night, hour)
}
}
PostUpdate (sdm220_hourcounter, hour)
End
Rule "Energy by day"
When
Time cron "0 0 0 * *?"
Then
Var day = sdm220_actcounter.state as DecimalType - sdm220_actcounter.historicState (now.minusDays (1), "mysql" :). State as DecimalType
// night counter, 00: 00..07: 00 + 23: 00..00: 00
Var day2 = sdm220_actcounter.historicState (now.minusHours (17), "mysql" :). State as DecimalType - sdm220_actcounter.historicState (now.minusDays (1), "mysql" :). State as DecimalType + sdm220_actcounter.state as DecimalType - sdm220_actcounter.historicState (now.minusHours (1), "mysql" :). State as DecimalType
// day counter, 07: 00..23: 00
Var day1 = sdm220_actcounter.historicState (now.minusHours (1), "mysql" :). State as DecimalType - sdm220_actcounter.historicState (now.minusHours (17), "mysql" :). State as DecimalType
LogInfo ("TEST", "sdm220_daycounter_day =" + day1)
LogInfo ("TEST", "sdm220_daycounter_night =" + day2)
LogInfo ("TEST", "sdm220_daycounter =" + day)
PostUpdate (sdm220_daycounter, day)
PostUpdate (sdm220_daycounter_day, day1)
PostUpdate (sdm220_daycounter_night, day2)
End
Before editing the script, add the required Items:
Number sdm220_hourcounter_day (gSDM220)
Number sdm220_hourcounter_night (gSDM220)
Number sdm220_daycounter_day (gSDM220)
Number sdm220_daycounter_night (gSDM220)
Now the schedule of hourly and daily consumption looks like this:
This is probably all. It is also planned to add the calculation of electricity and money consumption for the month at day and night rates and the generation of the report with sending to the post.