Syndicate content
Open-source tools for energy monitoring and visualisation
Updated: 1 day 1 hour ago

Emonhub installation/update, replacing the PHP raspberrypi emoncms module

Fri, 24/10/2014 - 11:58
From Paul Reed's post on the forums here:

Emonhub is now the recommended method of interfacing a rfm12pi to a local or remote emoncms install, and replaces the PHP and Python scripts which we have previously used.

Thanks to Paul Burnell, the author of emonhub, installation of emonhub can be achieved via a command line, which clones an installation script to automate the installation process.

To install emonhub:

$ git clone ~/dev-emonhub && ~/dev-emonhub/install

If you have the raspberry pi module already installed, it's important that it is removed prior to installing emonhub, as only one software can use the serial UART the RFM2Pi is connected to at any one time.

To remove the existing module, and then install emonhub, enter the following command line;

$ git clone ~/dev-emonhub && ~/dev-emonhub/upgrade

You will notice that after running this command, that emoncms will stop updating, this is expected until the configuration file is updated as follows;

$ nano /etc/emonhub/emonhub.conf

Enter your emoncms read/write api key in [[[runtimesettings]]] and also enter your rfm2pi frequency, group & base id under [[[runtimesettings]]]
Save your settings, and; $ sudo service emonhub restart

View the error log; $ tail -f /var/log/emonhub/emonhub.log

By default this is set to record 'WARNING', however this can be changed to either - DEBUG, INFO, WARNING, ERROR, and CRITICAL by editing the configuration file.


NOTE - This update will not orphan or alter your input processes, feeds, visualizations or feed data, as it only changes the way in which data is fed to emoncms.
Categories: Blog

From the Forum: Using Modbus RS485 to read a SDM630M 3-phase meter

Thu, 11/09/2014 - 12:20

JBecker writes :
I am using a modified OpenEnergyMonitor energy monitoring hardware since more than a year now, with one voltage sensor and three CTs for the current measurement of the three mains phases. This system logs via the RFM12 and a Jeelink USB dongle to Emoncms on a Windows Home Server. This setup is running very reliably with an accuracy of better than ~4% compared to my power meter. I think it would be possible to get better accuracy by using individual voltage sensors on all phases.
In Germany the majority of household have three phase supply. To be able to use three voltage sensors it would be necessary to have three outlets within the distribution (for non-invasive mounting). I have never seen that. This means that you have to ask a friendly electrician to install these outlets. But then the whole thing is not really 'non-invasive' any more (and the OEM solutions becomes quite complex with a lot of cabling). This is a dilemma which is hard to solve.
So I came to another solution which is quite simple and uses mostly ready-made components:
I am using Chinese 3-phase energy monitors since some time for professional purposes (PV-Systems with battery storage). A very nice unit of this type is the Eastron SDM630M. This device has integrated shunts for current measurement, a nice little display and an RS485 interface for data readout with Modbus protocol. A lot of measuring values can be read, including imported and exported energy, phase voltages, currents, frequency, reactive power and so on. Parameters for the RS485 can also be set via four small keys and the display.

For data storage and visualization I decided use the new Emoncms 'low-write' version on a Raspberry Pi. This was installed according to the installation instructions and worked 'out-of-the-box'. The only thing missing on the RasbPi for direct connection to the SDM630 is an RS485 interface.

To be able to use the already existing software for data collection on the RasPi (Emonhub), I simply made a 'clone' of the RFM12Pi module. This now has an RS485 driver onboard instead of the RFM12 RF transceiver. Software on the RS485Pi board is the Opti-bootloader (same as on RFM12Pi) for Arduino compatibility and a small sketch for data readout via modbus. As the only available hardware UART is already used for communication with the RasbPi I had to use a software serial for the RS485 interface. (The 'ModbusMasterSoft' library I use is a dirty hack of the existing ModbusMaster library and the AltSoftSerial library. I found no decent way to make these two work together, so I had to modify them)
So the whole installation now consists of:
- a Raspberry Pi with power supply and the RS485Pi interface board
- the SDM630 energy meter
(- and a cable in between :-))
See forum thread for schematic and code:

Written by Joerg Becker uses code from: - ModbusMaster library - AltSoftSerial library - pezibaer (SDM630M-DC thread in hardware 'cloned' from: - RFM12Pi (OpenEnergyMonitor, mharazinov) - 3V3 RS485 driver added - bootloader compatible to RFM12Pi ModbusMasterSoft is a dirty hack I made by combining the ModbusMaster library and the AltSoftSerial library. I was unable to combine these two in a decent way. The software serial is used for the RS485, hardware serial for Raspberry Pi connection */ #include <AltSoftSerial.h> #include <ModbusMasterSoft.h> // settings for RS485 bus (SDM630M can be configured to different values!) #define _SDM630M_MODBUS_ID 4 // Modbus address of SD630M energy monitor #define _MODBUS_BAUD 9600 // Modbus (RS485) baud rate // settings for communication with Raspberry Pi #define _INTERVAL 10 // send interval (s) to Raspberry Pi (running EmonCMS) #define _RASPI_BAUD 9600 // UART baud rate // some hardware definitions #define LED1_PIN A0 // RS485 activity LED #define LED2_PIN A1 // UART activity LED //AltSoftSerial AltSerial; // not needed here, done in ModbusMasterSoft // instantiate ModbusMaster object ModbusMasterSoft node(_SDM630M_MODBUS_ID); // float calculations are slow, but here we have enough processing time float v1,v2,v3; float i1,i2,i3; float p1,p2,p3,pa; float v1_sum,v2_sum,v3_sum; float v1_avg,v2_avg,v3_avg; float i1_sum,i2_sum,i3_sum; float i1_avg,i2_avg,i3_avg; float p1_sum,p2_sum,p3_sum,pa_sum; float p1_avg,p2_avg,p3_avg,pa_avg; uint32_t timeout; void setup() { pinMode(LED1_PIN, OUTPUT); pinMode(LED2_PIN, OUTPUT); digitalWrite(LED1_PIN, 0); digitalWrite(LED2_PIN, 0); Serial.begin(_RASPI_BAUD); Serial.println("SDM630M Test Program"); delay(1000); // initialize Modbus communication baud rate node.begin(_MODBUS_BAUD); timeout = millis(); } void loop() { static uint8_t interval = 0; uint8_t result; uint32_t tmpL; tmpL = millis(); if( (tmpL-timeout)>=1000 ) // do this every second { timeout = tmpL; digitalWrite(LED1_PIN, 1); digitalWrite(LED2_PIN, 0); ReadVoltages(); v1_sum += v1; v2_sum += v2; v3_sum += v3; ReadCurrents(); i1_sum += i1; i2_sum += i2; i3_sum += i3; ReadPowers(); p1_sum += p1; p2_sum += p2; p3_sum += p3; pa_sum += pa; if( ++interval>=_INTERVAL ) { interval = 0; v1_avg = v1_sum*10/_INTERVAL; // preserve one (of two) decimal digit(s) v2_avg = v2_sum*10/_INTERVAL; v3_avg = v3_sum*10/_INTERVAL; v1_sum = v2_sum = v3_sum = 0; i1_avg = i1_sum/_INTERVAL; i2_avg = i2_sum/_INTERVAL; i3_avg = i3_sum/_INTERVAL; i1_sum = i2_sum = i3_sum = 0; p1_avg = p1_sum/_INTERVAL; p2_avg = p2_sum/_INTERVAL; p3_avg = p3_sum/_INTERVAL; pa_avg = pa_sum/_INTERVAL; p1_sum = p2_sum = p3_sum = pa_sum = 0; digitalWrite(LED2_PIN, 1); PrintJeelink(); } digitalWrite(LED1_PIN, 0); } } void PrintJeelink(void) { unsigned char i; union DATA { unsigned char item[]; struct { int P1; int P2; int P3; int V1; int V2; int V3; } val; } data; data.val.P1 = (int)(p1_avg+0.5); data.val.P2 = (int)(p2_avg+0.5); data.val.P3 = (int)(p3_avg+0.5); data.val.V1 = (int)(v1_avg+0.5); data.val.V2 = (int)(v2_avg+0.5); data.val.V3 = (int)(v3_avg+0.5); Serial.print(" 10"); // this is data from 'node' number 10 for(i=0;i<sizeof(data.val);i++) { Serial.print(" "); Serial.print(data.item[i]); } Serial.println(); } uint8_t ReadVoltages( void ) { uint8_t result; uint32_t val; result = node.readInputRegisters(0x0000, 6); // read Modbus registers 0 to 5 if (result == node.ku8MBSuccess) { val = ((uint32_t)node.getResponseBuffer(0))<<16 |((uint32_t)node.getResponseBuffer(1)); memcpy(&v1, &val, 4); val = ((uint32_t)node.getResponseBuffer(2))<<16 |((uint32_t)node.getResponseBuffer(3)); memcpy(&v2, &val, 4); val = ((uint32_t)node.getResponseBuffer(4))<<16 |((uint32_t)node.getResponseBuffer(5)); memcpy(&v3, &val, 4); } return result; } uint8_t ReadCurrents( void ) { uint8_t result; uint32_t val; result = node.readInputRegisters(0x0006, 6); // read Modbus registers 6 to 11 if (result == node.ku8MBSuccess) { val = ((uint32_t)node.getResponseBuffer(0))<<16 |((uint32_t)node.getResponseBuffer(1)); memcpy(&i1, &val, 4); val = ((uint32_t)node.getResponseBuffer(2))<<16 |((uint32_t)node.getResponseBuffer(3)); memcpy(&i2, &val, 4); val = ((uint32_t)node.getResponseBuffer(4))<<16 |((uint32_t)node.getResponseBuffer(5)); memcpy(&i3, &val, 4); } return result; } uint8_t ReadPowers( void ) { uint8_t result; uint32_t val; result = node.readInputRegisters(0x000C, 6); // read Modbus registers 12 to 17 if (result == node.ku8MBSuccess) { val = ((uint32_t)node.getResponseBuffer(0))<<16 |((uint32_t)node.getResponseBuffer(1)); memcpy(&p1, &val, 4); val = ((uint32_t)node.getResponseBuffer(2))<<16 |((uint32_t)node.getResponseBuffer(3)); memcpy(&p2, &val, 4); val = ((uint32_t)node.getResponseBuffer(4))<<16 |((uint32_t)node.getResponseBuffer(5)); memcpy(&p3, &val, 4); } return result; } ]]>
Categories: Blog