If you’re wanting to monitor your energy consumption (or your energy created from your solar panels), you probably have an smart meter in your home. I bought the sml reader from “Udo” (http://wiki.volkszaehler.org/hardware/controllers/ir-schreib-lesekopf), but every other sml reader should do.
So at first, connect the sml reader to your smart meter and unlock it with a lamp (they are usually PIN-locked, when installed). So if it’s unlocked proceed with the following:
- install libsml (a simple C-program for reading out the sml Reader)
- configure libsml
- add items to the openHAB
- add a rule for populating the items values
compile libsml
Normally in the raspbian distributions for a Raspberry Pi (wich is also used in openHABian), the essentials for compiling should be already installed, just to be sure, start with updating the packages and installing the building tools (I’m refering to a bebian-based package installation via apt-get, perhaps you have to adjust this, if you’re using a different OS) :
sudo apt-get update && sudo apt-get upgrade sudo apt-get install build-essentials
Now we’re going to install libsml in /usr/src, if you want it somewhere else, just change the line above:
sudo apt-get update && sudo apt-get upgrade sudo apt-get install uuid-dev uuid-runtime cd /usr/src git clone https://github.com/dailab/libsml.git cd libsml sudo make
you should now have the library installed, and we can proceed with tests. Before testing, you must check, whether your user is allowed to access the programm - and the device (in my case USB).
Be aware, that after Installation, you want openHAB to execute the program, just for the learning effect and simplicity, I’m using the pi-User for the tests until handing over to openHAB later.
cd /usr/src sudo chown pi:pi examples cd examples sudo chown pi:pi * dmesg |grep pl23
the last command shows you the (USB-)devices for the IR-readers. Usually it will be /dev/ttyUSB0
With that in mind, we can go over configuring libsml.
configuring libsml
In the Example directory is the code in a sml_server.c
file, which we have to adjust:
sudo nano sml_server.c
- change the line
char *device="/dev/ttyUSB0";
withchar *device=argv[1];
with this change, we’re able to use the program with the device as an argument, useful for more than one reader - change the whole function
transport_receiver
with:
void transport_receiver(unsigned char *buffer, size_t buffer_len) {
// Danke an Axel (tuxedo) für seinen Beispielcode
int i;
double value;
sml_file *file = sml_file_parse(buffer + 8, buffer_len - 16);
// the sml file is parsed now
for (i = 0; i < file->messages_len; i++) {
sml_message *message = file->messages[i];
if (*message->message_body->tag == SML_MESSAGE_GET_LIST_RESPONSE) {
sml_list *entry;
sml_get_list_response *body;
body = (sml_get_list_response *) message->message_body->data;
for (entry = body->val_list; entry != NULL; entry = entry->next) {
switch (entry->value->type) {
case 0x51: value= *entry->value->data.int8; break;
case 0x52: value= *entry->value->data.int16; break;
case 0x54: value= *entry->value->data.int32; break;
case 0x58: value= *entry->value->data.int64; break;
case 0x61: value= *entry->value->data.uint8; break;
case 0x62: value= *entry->value->data.uint16; break;
case 0x64: value= *entry->value->data.uint32; break;
case 0x68: value= *entry->value->data.uint64; break;
default:
value = 0;
}
int scaler = (entry->scaler) ? *entry->scaler : 1;
if (scaler==-1)
value *= 0.0001;
if (value) {
printf("%d-%d:%d.%d.%d*%d#%.3f#\n",
entry->obj_name->str[0], entry->obj_name->str[1],
entry->obj_name->str[2], entry->obj_name->str[3],
entry->obj_name->str[4], entry->obj_name->str[5], value);
}
}
sml_file_free(file);
exit(0); // processed first message - exit
}
}
}
at the end, we compile the programm again: sudo make
Testing the output:
/usr/src/libsml/examples/sml_server /dev/ttyUSB0
should now result in a reading like this:
pi@raspberrypi:~ $ /usr/src/libsml/examples/sml_server /dev/ttyUSB0
1-0:1.8.0*255#19210.031#
1-0:1.8.1*255#19210.031#
1-0:16.7.0*255#0.484#
So I figure, the first two lines tell me the overall meter consumption and the last and third line tell me the actual power consumption at the moment.
With this information in mind, we can now configure openHAB to execute the programm, read the output and parse it to update the items.
items and rules in openHAB
as mentioned above, we want openHAB to execute the sml_server
program, so we have to be sure, that our settings and rights are in line to do that. In my example, I concentrate on using Rasbian and more specific openHABian. Perhaps you have to adjust the users and rights to your needs, if using another OS or openHAB-installation.
configuring rasbian for letting openHAB execute the program
sudo addgroup openhab tty, dialout cd /usr/src/ copy /usr/src/libsml/examples/sml_server ./ sudo chown openhab:openhab sml_server
with this we added the openhab-user to the Groups “tty” and “dialout”. I’m not sure, at least the OH-user should be in the tty-group, but it doesn’t do damage, if he’s also in the dialout-group. Only then, the user is allowed to use USB-devices.
we also copied the program from examples to the /usr/src and changed the owner of the sml_server program to “openhab”, so, this user can execute the program.
So, wer’re ready to add the .items:
Number sensors_consumption_power "power consumption [%.1f kwh]"
Number sensors_status_power "power status [%.1f kwh]"
first one will tell the present power consumption, second one shows the status of the power meter.
lastly, we set up the rule for executing the program and updating the items:
rule "power meter"
when
Time cron "0,30 */1 * * * ?" // this one cycles every 30 seconds. depends on your needs
then
// getting the payload of the meter
var String meter_payload = executeCommandLine("/usr/src/sml_server /dev/ttyUSB0", 5000) // note the argument /dev/ttyUSB0 - your meter-device-id goes here
// splitting the payload - first in lines, then getting counterStr and consumptionStr with delimiter "#"
val lines = meter_payload.split('\n')
val counterStr = lines.get(0).split('#').get(1)
val consumptionStr = lines.get(2).split('#').get(1)
// Updating the items
if (sensors_status_power.state != counterStr) sensors_status_power.sendCommand(counterStr)
sensors_consumption_power.postUpdate(consumptionStr)
end
That’s it. Now you should get an update on the power meter, regarding to the cycle-time you setup in the rule.