Created
November 5, 2016 13:52
-
-
Save mattiarossi/8ad369cd8fb0497aff4f7425f4e967de to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/python | |
| # -*- coding: utf-8 -*- | |
| # @Author: mattiarossi | |
| # @Date: 2016-03-27 23:29:25 | |
| # @Last Modified by: mattiarossi | |
| # @Last Modified time: 2016-03-28 23:25:55 | |
| import time | |
| import threading | |
| import minimalmodbus | |
| minimalmodbus.CLOSE_PORT_AFTER_EACH_CALL = False | |
| import paho.mqtt.client as mqtt | |
| import pprint | |
| import json | |
| # state values | |
| stateDict = {} | |
| user="sdmmonitor" | |
| passwd="ewuriwyurywiryei" | |
| clientid="emonpi01sdmmon" | |
| server="" | |
| topic="ha/value/electricity/" | |
| addresslist={'1': 'generale', '2': 'casa' , '3': 'condizionatori','4':'lavanderia','5':'ups-pc','6':'solar','7':'enel'} | |
| masterMsgInterval = 10 | |
| singleInstrumentInterval=0.5 | |
| cleansession = False | |
| sessionConnected = False | |
| rs485Instances=[] | |
| # MQTT broker callbacks | |
| def on_connect(mosq, userdata, result_code): | |
| """ | |
| Handle connections (or failures) to the broker. | |
| This is called after the client has received a CONNACK message | |
| from the broker in response to calling connect(). | |
| The result_code is one of; | |
| 0: Success | |
| 1: Refused - unacceptable protocol version | |
| 2: Refused - identifier rejected | |
| 3: Refused - server unavailable | |
| 4: Refused - bad user name or password (MQTT v3.1 broker only) | |
| 5: Refused - not authorised (MQTT v3.1 broker only) | |
| """ | |
| if result_code == 0: | |
| print("Connected to MQTT broker, subscribing to topics...") | |
| if not cleansession: | |
| print("Cleansession==False; previous subscriptions for clientid %s remain active on broker" % clientid) | |
| elif result_code == 1: | |
| print("Connection refused - unacceptable protocol version") | |
| elif result_code == 2: | |
| print("Connection refused - identifier rejected") | |
| elif result_code == 3: | |
| print("Connection refused - server unavailable") | |
| elif result_code == 4: | |
| print("Connection refused - bad user name or password") | |
| elif result_code == 5: | |
| print("Connection refused - not authorised") | |
| else: | |
| print("Connection failed - result code %d" % (result_code)) | |
| def on_disconnect(mosq, userdata, result_code): | |
| global sessionConnected | |
| """ | |
| Handle disconnections from the broker | |
| """ | |
| if result_code == 0: | |
| print("Clean disconnection from broker") | |
| else: | |
| print("brokerdisconnected", "Broker connection lost. Will attempt to reconnect in 5s...") | |
| time.sleep(5) | |
| sessionConnected = False | |
| sys.exit(0) | |
| def readRs485Data(): | |
| global rs485Instances, stateDict | |
| stateDict = {} | |
| for rsInstance in rs485Instances: | |
| counterDict = {} | |
| print rsInstance | |
| try: | |
| counterDict['Volts'] = rsInstance.read_float(0, functioncode=4, numberOfRegisters=2) | |
| counterDict['Current'] = rsInstance.read_float(6, functioncode=4, numberOfRegisters=2) | |
| counterDict['Active_Power'] = rsInstance.read_float(12, functioncode=4, numberOfRegisters=2) | |
| counterDict['Apparent_Power'] = rsInstance.read_float(18, functioncode=4, numberOfRegisters=2) | |
| counterDict['Reactive_Power'] = rsInstance.read_float(24, functioncode=4, numberOfRegisters=2) | |
| counterDict['Power_Factor'] = rsInstance.read_float(30, functioncode=4, numberOfRegisters=2) | |
| counterDict['Phase_Angle'] = rsInstance.read_float(36, functioncode=4, numberOfRegisters=2) | |
| counterDict['Frequency'] = rsInstance.read_float(70, functioncode=4, numberOfRegisters=2) | |
| counterDict['Import_Active_Energy'] = rsInstance.read_float(72, functioncode=4, numberOfRegisters=2) | |
| counterDict['Export_Active_Energy'] = rsInstance.read_float(74, functioncode=4, numberOfRegisters=2) | |
| counterDict['Import_Reactive_Energy'] = rsInstance.read_float(76, functioncode=4, numberOfRegisters=2) | |
| counterDict['Export_Reactive_Energy'] = rsInstance.read_float(78, functioncode=4, numberOfRegisters=2) | |
| counterDict['Total_Active_Energy'] = rsInstance.read_float(342, functioncode=4, numberOfRegisters=2) | |
| counterDict['Total_Reactive_Energy'] = rsInstance.read_float(344, functioncode=4, numberOfRegisters=2) | |
| counterDict['Current_Yield'] = counterDict['Volts']*counterDict['Current'] | |
| if (rsInstance.address == 6): | |
| counterDict['Solar_Export']= counterDict['Active_Power'] - stateDict[addresslist['1']]['Active_Power'] | |
| if (counterDict['Solar_Export'] < 0): | |
| counterDict['Solar_Export'] = 0 | |
| counterDict['Grid_Import']= stateDict[addresslist['1']]['Active_Power'] - counterDict['Active_Power'] | |
| if (counterDict['Grid_Import'] < 0): | |
| counterDict['Grid_Import'] = 0 | |
| stateDict[addresslist[str(rsInstance.address)]] = counterDict | |
| time.sleep(singleInstrumentInterval) | |
| #print 'Voltage: {0:.1f} Volts'.format(Volts) | |
| #print 'Current: {0:.1f} Amps'.format(Current) | |
| #print 'Active power: {0:.1f} Watts'.format(Active_Power) | |
| #print 'Apparent power: {0:.1f} VoltAmps'.format(Apparent_Power) | |
| #print 'Reactive power: {0:.1f} VAr'.format(Reactive_Power) | |
| #print 'Power factor: {0:.1f}'.format(Power_Factor) | |
| #print 'Phase angle: {0:.1f} Degree'.format(Phase_Angle) | |
| #print 'Frequency: {0:.1f} Hz'.format(Frequency) | |
| #print 'Import active energy: {0:.3f} Kwh'.format(Import_Active_Energy) | |
| #print 'Export active energy: {0:.3f} kwh'.format(Export_Active_Energy) | |
| #print 'Import reactive energy: {0:.3f} kvarh'.format(Import_Reactive_Energy) | |
| #print 'Export reactive energy: {0:.3f} kvarh'.format(Export_Reactive_Energy) | |
| #print 'Total active energy: {0:.3f} kwh'.format(Total_Active_Energy) | |
| #print 'Total reactive energy: {0:.3f} kvarh'.format(Total_Reactive_Energy) | |
| #print 'Current Yield (V*A): {0:.1f} Watt'.format(Volts * Current) | |
| # | |
| except Exception, e: | |
| print "----> 2 ----> Error" | |
| print str(e) | |
| pass | |
| mqttc = mqtt.Client(client_id=clientid) | |
| mqttc.username_pw_set(user, passwd) | |
| mqttc.on_connect = on_connect | |
| mqttc.on_disconnect = on_disconnect | |
| mqttc.connect(server) | |
| sessionConnected = True | |
| for slaveAddr,slaveName in addresslist.iteritems(): | |
| print "Adding instrument " ,slaveAddr | |
| rs485 = minimalmodbus.Instrument('/dev/ttyUSB0', int(slaveAddr)) | |
| rs485.serial.baudrate = 9600 | |
| rs485.serial.bytesize = 8 | |
| rs485.serial.parity = minimalmodbus.serial.PARITY_NONE | |
| rs485.serial.stopbits = 1 | |
| rs485.serial.timeout = 1 | |
| rs485.debug = False | |
| rs485.mode = minimalmodbus.MODE_RTU | |
| rs485Instances.append(rs485) | |
| while True: | |
| readRs485Data() | |
| # send to MQTT | |
| try: | |
| for key,values in stateDict.iteritems(): | |
| baseTopic = topic + "counter/"+ str(key) + "/" | |
| #print "Publishing values %s to topic %s",str(values),baseTopic | |
| for t,v in values.iteritems(): | |
| fTopic = baseTopic + t | |
| fTopic2 = "emon/"+ str(key) + "/" + t | |
| #print "["+fTopic+"]: " + str(v) | |
| if sessionConnected == False : | |
| print "-----------> Reconnecting ----------" | |
| mqttc.reconnect() | |
| sessionConnected = True | |
| mqttc.publish(fTopic, v, 1) | |
| mqttc.publish(fTopic2, v, 1) | |
| mqttc.loop(2,10) | |
| except Exception as ex: | |
| print "MQTT Exception: " + str(ex) | |
| sys.exit(0) | |
| time.sleep(masterMsgInterval) | |
| mqttc.disconnect() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment