chuck-h / SteVe-SC

6 stars 1 forks source link

Modbus for current sensors #3

Open chuck-h opened 5 years ago

chuck-h commented 5 years ago

Many industrial current sensors (including those embedded in overload relays #2) report via modbus protocol. Need a pathway to get this information into LoadManager.

Could use commercial modbus gateway
image
or equivalent software mbusd on RPi:
image

chuck-h commented 5 years ago

Modbus-json conversion might be written in python and use pymodbus https://github.com/riptideio/pymodbus

Related work on emonhub here https://github.com/openenergymonitor/emonhub/pull/14

chuck-h commented 5 years ago

image

chuck-h commented 5 years ago

Checked Eaton C440 with C440-XCOM module, FTDI USB-485 adapter, qModMaster; able to read & write registers.

chuck-h commented 5 years ago

mbusd on RPi3 works just as described here: https://medium.com/@boonsanti/raspberry-pi-3-model-b-modbus-rs-485-to-modbus-tcp-ip-gateway-9ed14ce2c08e
qModMaster in TCP mode sees/controls C440 thru RPi

chuck-h commented 5 years ago

Example assembly
ol_overview

USB-RS485 converter:
image
Eaton C440-XCOM Modbus connection:
image

Eaton C440 User Manual includes modbus register definitions:
MN04210004E.pdf

mbusd configuration file:

chuck@pi3:~$ cat /etc/mbusd/mbusd-ttyUSB0.conf
#############################################
#                                           #
#    Sample configuration file for mbusd    #
#                                           #
#############################################

########## Serial port settings #############

# Serial port device name
device = /dev/ttyUSB0

# Serial port speed
speed = 19200

# Serial port mode
mode = 8e1

# RS-485 data direction control type (addc, rts, sysfs_0, sysfs_1)
trx_control = addc

# Sysfs file to use to control data direction
# trx_sysfile =

############# TCP port settings #############

# TCP server port number
port = 502

# Maximum number of simultaneous TCP connections
maxconn = 32

# Connection timeout value in seconds
timeout = 60

######### Request/response settings #########

# Maximum number of request retries
retries = 3

# Pause between requests in milliseconds
pause = 100

# Response wait time in milliseconds
wait = 500

Python script to report readings in "emoncms" JSON style

#!/usr/bin/env python

import time
import requests
import subprocess

targets = [ {'url': "http://192.168.0.221/emoncms/input/post",
             'apikey': '5886165e519b057c86165e519b057cb2',
             'node': 'current_test'},
            {'url': "http://192.168.0.222:9092/loadmanager/input/post",
             'apikey':  '',
             'node': 'shop_panel_OL'}
          ]

from pymodbus.client.sync import ModbusTcpClient

C440_regs = {'OL_state':300,'I_phaseA':301,'I_phaseB':302,'I_phaseC':303,'Iavg':304,
             'Thermal_pct':305,'Faults':306,'I_pctFLA':307,'Imbal_pct':308,'GF_pct':309,
             'I_gnd':310,'FLA_set':311,'OL_Class':312,'LineFreq':313,'Feature_state':314,
             'Temp_C':315,'BoostV_mV':316,'Vcc_mV':317,'Expan_ID':318,
             'Trip_reset':332,
             'Modbus_addr':364,
             'IFLA_min':396,'IFLA_max':397,'I_multiplier':398,'ProdCode':399, 'Serial32':400}

polled_points = ['OL_state', 'I_phaseA', 'I_phaseB', 'I_phaseC', 'I_multiplier', 'Faults']
poll_interval_sec = 5
while True:
    try:
        my_ip = subprocess.Popen("ifconfig wlan0 | grep -o 'inet addr:[0-9.]*' | tail -c+11", shell=True, stdout=subprocess.PIPE).stdout.read()
        print my_ip
        client = ModbusTcpClient(my_ip)
        while True:
            time.sleep(poll_interval_sec)
            polled_data = {}
            for p in polled_points:
                polled_data[p] = client.read_holding_registers(C440_regs[p]-1, 1, unit=1).registers[0]
            print(polled_data)
            for target in targets:
                #print(target)
                try:
                    data = {'node':target['node'], 'fulljson':'{"phase1":%2.1f, "phase2":%2.1f, "state":%d}'% \
                              ((int(polled_data['I_phaseA'])*1.0/polled_data['I_multiplier']),
                               (int(polled_data['I_phaseC'])*1.0/polled_data['I_multiplier']),
                               (int(polled_data['OL_state']))),
                            'apikey':target['apikey']}
                    r = requests.post(url = target['url'], data = data, timeout = 1)
                except Exception as e:
                    print("data post to " + target['url'] + " failed:\n" + str(e))
            #print(r.text)

    except Exception as e:
        print(e)
        client.close()
        time.sleep(10)
chuck-h commented 4 years ago

Running the above python script on Raspberry Pi 3 under Ubuntu 16.04, there was an issue with the system failing to recover after an extended Wifi outage. Following these instructions for nm-watcher service seemed to solve this.
https://askubuntu.com/questions/71528/make-network-manager-restart-after-dropped-connection