OWL Intuition Power Meter Data into OpenHAB

Tags: #<Tag:0x00007f617eb88e68> #<Tag:0x00007f617eb88c38> #<Tag:0x00007f617eb88ad0>

Hi there,

I’ve had an OWL Intuition power meter for two years now, I was planning to switch it for a Z-Wave power meter, but never got around to it. Recently I found out that the OWL sends its power data in XML format over multicast (example code here).

I have 3-phase electricity and 3-pase solar monitoring on the same OWL.

A couple of users here have implemented partly working solutions, but they didn’t work for me. In the end, I managed to modify a python script that I found so that it suited my needs. Then the output from this script is used by a shell script to send JSON lines over MQTT.
I’m running all this on a RaspberryPi, as well as OpenHAB.

Here is the python script, which I very crudely modified to output each channel read from the OWL meter.

import socket
import struct
import json
from xml.etree import ElementTree as ET

OWL_PORT = 22600
OWL_GROUP = "224.192.32.19"

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((OWL_GROUP, OWL_PORT))
mreq = struct.pack("=4sl", socket.inet_aton(OWL_GROUP), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)

while True:
    # Collect the XML multicast message
    xml, addr = sock.recvfrom(1024)
    # Parse the XML string
    root = ET.fromstring(xml)

    # Only process those messages we are interested in
    if root.tag == 'electricity' or root.tag == 'solar':
    
        timestamp_value = 0
        timestamp = root.find('timestamp')
        if timestamp is not None:
            timestamp_value = int(timestamp.text)
    
        # iterate over each zone (Owl supports up to 4), but we don't distinguish
        for chan in root.iter('chan'):

            chan_value = 0
            #chanid = chan.find('chan')
            #if chanid is not None:
	    chan_value = int(chan.attrib["id"])

            current_value = 0.0
            current = chan.find('curr')
            if current is not None:
                current_value = float(current.text)


      #      required_value = 0.0
      #      required = zone.find('temperature/required')
      #      if required is not None:
      #          required_value = float(required.text)

      #      ambient_value = 0.0
      #      ambient = zone.find('temperature/ambient')
      #      if ambient is not None:
      #          ambient_value = float(ambient.text)

            print json.dumps({'device': root.tag, \
                        'timestamp': timestamp_value, \
       #                 'battery_level': battery_value, \
                        'chan_id': chan_value, \
                        'current_watts': current_value, \
       #                 'current_solar': current_gen_value, \
       #                 'required_temperature': required_value, \
       #                 'ambient_temperature': ambient_value 
})

This outputs something like this:

{"device": "electricity", "timestamp": 1551118108, "current_watts": 209.0, "chan_id": 0}
{"device": "electricity", "timestamp": 1551118108, "current_watts": 177.0, "chan_id": 1}
{"device": "electricity", "timestamp": 1551118108, "current_watts": 80.0, "chan_id": 2}
{"device": "electricity", "timestamp": 1551118108, "current_watts": 16.0, "chan_id": 3}
{"device": "electricity", "timestamp": 1551118108, "current_watts": 33.0, "chan_id": 4}
{"device": "electricity", "timestamp": 1551118108, "current_watts": 16.0, "chan_id": 5}

Channels 0, 1, 2 are the power consumption of each phase;
Channels 3, 4, 5 are solar generation.
Other metrics are available but these were the ones I needed the most, all others can be extrapolated by OpenHAB.

Then this shell script takes this output and sends it over MQTT:

#!/bin/sh
#
# owl_mcast2mqtt.sh
#
# Publish json output of the owl_mcast2json script to MQTT 
#
#export LANG=C
#PATH="/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin"

MQTT_HOST="10.0.0.77"
MQTT_USER="user"
MQTT_PASS="password"

#echo "OWL Network Multicast 2 MQTT"

python -u intu.py | while read line
do
#	MQTT_TOPIC="home/mcast/$(echo $line | jq --raw-output '.device')"
	MQTT_TOPIC="$(echo $line | jq --raw-output '.chan_id')"
	# Publish the json to the appropriate topic
	echo $line | mosquitto_pub -h $MQTT_HOST -u $MQTT_USER -P $MQTT_PASS -i OWL_MCast -r -l -t /home/mcast/electricity/$MQTT_TOPIC
done

This script sends each channel reading on its own MQTT topic at

/home/mcast/electricity/0
/home/mcast/electricity/1
/home/mcast/electricity/2
/home/mcast/electricity/3
/home/mcast/electricity/4
/home/mcast/electricity/5

You only need to run this script, which in turn calls the first one, and you should set it up to run on boot, or cron, or whatever way you prefer.

Then you just need to setup items with a JSONPATH transform:

Number Fase1 "Consumo Fase 1 [%d W]"    (Tudo)          {mqtt="<[mybroker:/home/mcast/electricity/0:state:JSONPATH($.current_watts)]"}
Number Fase2 "Consumo Fase 2 [%d W]"    (Tudo)          {mqtt="<[mybroker:/home/mcast/electricity/1:state:JSONPATH($.current_watts)]"}
Number Fase3 "Consumo Fase 3 [%d W]"    (Tudo)          {mqtt="<[mybroker:/home/mcast/electricity/2:state:JSONPATH($.current_watts)]"}


Number SolFase1 "Solar Fase 1 [%d W]"   (Tudo)          {mqtt="<[mybroker:/home/mcast/electricity/3:state:JSONPATH($.current_watts)]"}
Number SolFase2 "Solar Fase 2 [%d W]"   (Tudo)          {mqtt="<[mybroker:/home/mcast/electricity/4:state:JSONPATH($.current_watts)]"}
Number SolFase3 "Solar Fase 3 [%d W]"   (Tudo)          {mqtt="<[mybroker:/home/mcast/electricity/5:state:JSONPATH($.current_watts)]"}

Hope this helps someone! Cheers!

2 Likes