Revised immerSUN Monitoring

I have re-worked the monitoring solution for the immerSUN solar PV diverter which is responsible for measuring the house’s electricity consumption, the import of electricity from the grid, the solar PV generation and any diversion of excess solar generation to the domestic hot water cylinder’s immersion heater.

Previously the monitoring was done by extracting data from the live.myimmersun.com webpage every minute and storing it in InfluxDB for visualization using Grafana. This worked OK but missed a lot of the details of how the readings change on a more dynamic basis. The immerSUN unit actually sends data in the form of a 56-byte UDP Datagram every 5 seconds and since this data is traversing the local network anyway it seems a shame not to extract the readings “on the way past”. While not trivial, since the format of the 56-byte Datagram is not published, it’s not that hard to reverse engineer where the different readings are.

There’s a (draft) write-up of the solution under the Technical Articles here.

M-Bus Water Meter Readings

In addition to the usual supply meters, there are a set of sub-meters in the house to report on particular aspects of resource consumption:

  • Water Meters, to assess how the water usage is broken down (e.g. hot water versus cold water)
    • One on the incoming cold water main
    • One on the separate incoming cold main which supplies the WCs, washing machine and outside taps and might, in future, be connected to a rainwater harvesting system
    • One on the cold supply pipe to the domestic hot water cylinder
      • This measures hot water usage based on the cold water used to top-up the cylinder as the hot water is used (it is generally better to meter  cold water than hot water)
      • This water also flows through the “incoming cold water main” meter so needs to be subtracted from that to calculate the cold water consumption
  • Heat Meters, to enable the real-world Coefficient of Performance of the Ground Source Heat Pump to be measured
    • One on the Central Heating output from the GSHP
    • One on the Water Heating output from the GSHP (likely to be a lower CoP because of the higher temperatures required)
  • Electricity Meters, to assess the consumption of some high-usage appliances

While it’s perfectly possible to read these meters manually (which is what I have been doing, on the first day of every month) the plan was always to read them automatically and to log the usage on a much more frequent basis. In line with my policy of using non-proprietary standards with good Open Source software support I settled on using the Meter-Bus standard (usually abbreviated to M-Bus, not to be confused with Modbus) to do this and hence specified / purchased meters with M-Bus interfaces.

(Actually, most of the Electricity meters don’t have M-Bus interfaces since those only seem to be available on the higher-capacity meters – 80A or so – and they attract a very high price premium. For the low-current sub-meters I used small DIN-Rail mounting meters with S0 pulse outputs rather than M-Bus interfaces, on the basis that it was better to have a simple meter than no meter at all.)

I cover a lot of the technical aspects of M-Bus on my M-Bus Meter Data Collection Page so see that for more details. The event that prompted this Post is that I’ve just got the water meter data collection working. It took me an embarrassingly long time to spot that the Itron Aquadis water meters were initially supplied with Pulse-Counting Cyble modules rather than M-Bus Cyble modules and once that was corrected it took a while to get the right version of the software needed to configure those. Kudos to the team at MWA Technology in Birmingham for helping me out (and no thanks to Itron for being thoroughly unhelpful – they only seem to want to deal with their big distributors).

I’ve found the best way to talk to an M-Bus meter from Linux is using the libmbus software. Basically this provides two data access mechanisms:

  • Using the generic mbus-serial-request-data utility to dump out all the data from a meter to an XML data string
  • Using the libmbus C API functions directly in your own code to grab the relevant subset of the data

I briefly toyed with the idea of writing a Perl module to map the C API to Perl so I could call it directly from a Perl script and then I wrote a simple C program to grab a limited set of data using the C API. However, in the end, I decided it was better to go down the XML route and to parse the full XML output string to extract the necessary data fields. I’ve written a Perl script which runs continuously (on the Raspberry Pi connected via an RS-232 interface to the M-Bus protocol converter) and extracts the data from all the M-Bus meters every few minutes. It then publishes the readings as messages using MQTT from where they follow the same route of logging and graphing used for other monitoring (Telegraf -> InfluxDB -> Grafana).

Some observations:

  • The request to read the M-Bus data seems to fail on a fairly regular basis (10-20% of the time) so the script needs to check for that and re-run the query until a response is received from each meter
  • The water meters report usage units of whole litres only (listed as milli cubic metres in the M-Bus response) which seems like quite a”chunky” response compared to some of the other meter readings
  • I found it was best to subtract the hot water reading from the cold water reading within the script and to create a further virtual meter for the difference (i.e. the actual cold water consumption)
  • I’m still working on how often to grab the data (currently every 2 minutes) and how best to present it (currently graphed as a “derivative” value of litres / minute)

An example of the full XML response from one of the Itron Aquadis water meters with an M-Bus Cyble communications module installed is shown below. Only the block highlighted in bold is really of interest (and actually it’s only the Value of 20312 which changes – that’s the same as displayed on the meter readout).

<?xml version="1.0" encoding="ISO-8859-1"?>
<MBusData>

 <SlaveInformation>
     <Id>17003877</Id>
     <Manufacturer>ACW</Manufacturer>
     <Version>20</Version>
     <ProductName>Itron CYBLE M-Bus 1.4</ProductName>
     <Medium>Water</Medium>
     <AccessNumber>23</AccessNumber>
     <Status>00</Status>
     <Signature>0000</Signature>
 </SlaveInformation>

 <DataRecord id="0">
     <Function>Instantaneous value</Function>
     <StorageNumber>0</StorageNumber>
     <Unit>Fabrication number</Unit>
     <Value>17003877</Value>
     <Timestamp>2017-06-30T08:03:19</Timestamp>
 </DataRecord>

 <DataRecord id="1">
     <Function>Instantaneous value</Function>
     <StorageNumber>0</StorageNumber>
     <Unit>cust. ID</Unit>
     <Value>0A        </Value>
     <Timestamp>2017-06-30T08:03:19</Timestamp>
 </DataRecord>

 <DataRecord id="2">
     <Function>Instantaneous value</Function>
     <StorageNumber>0</StorageNumber>
     <Unit>Time Point (time &amp; date)</Unit>
     <Value>2017-06-30T09:02:00</Value>
     <Timestamp>2017-06-30T08:03:19</Timestamp>
 </DataRecord>

 <DataRecord id="3">
     <Function>Instantaneous value</Function>
     <StorageNumber>0</StorageNumber>
     <Unit>bat. time</Unit>
     <Value>5352</Value>
     <Timestamp>2017-06-30T08:03:19</Timestamp>
 </DataRecord>

 <DataRecord id="4">
     <Function>Instantaneous value</Function>
     <StorageNumber>0</StorageNumber>
     <Unit>Volume (m m^3)</Unit>
     <Value>20312</Value>
     <Timestamp>2017-06-30T08:03:19</Timestamp>
 </DataRecord>

 <DataRecord id="5">
     <Function>Instantaneous value</Function>
     <StorageNumber>0</StorageNumber>
     <Unit>Volume (m m^3)</Unit>
     <Value>0</Value>
     <Timestamp>2017-06-30T08:03:19</Timestamp>
 </DataRecord>

 <DataRecord id="6">
     <Function>Instantaneous value</Function>
     <StorageNumber>1</StorageNumber>
     <Unit>Volume (m m^3)</Unit>
     <Value>0</Value>
     <Timestamp>2017-06-30T08:03:19</Timestamp>
 </DataRecord>

 <DataRecord id="7">
     <Function>Manufacturer specific</Function>
     <Value>00 01 1F</Value>
     <Timestamp>2017-06-30T08:03:19</Timestamp>
 </DataRecord>

</MBusData>