Skip to content

Commit

Permalink
Merge pull request #44 from segaura/logrevision
Browse files Browse the repository at this point in the history
mqttdaemon mode
  • Loading branch information
Spanni26 authored Apr 6, 2021
2 parents 4f0352e + c012194 commit 225d612
Show file tree
Hide file tree
Showing 10 changed files with 518 additions and 376 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
text=auto
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
install_pyHPSU
install
.vscode/settings.json
.vscode/launch.json
.vscode/launch.json
.vscode/.ropeproject/**
8 changes: 5 additions & 3 deletions HPSU/HPSU.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ def __init__(self, logger=None, driver=None, port=None, cmd=None, lg_code=None):
if not self.listCommands: #if we don't get a dict with commands

# get language, if non given, take it from the system
LANG_CODE = lg_code.upper()[0:2] if lg_code else locale.getdefaultlocale()[0].split('_')[0].upper()
LANG_CODE = lg_code[0:2] if lg_code else locale.getdefaultlocale()[0].split('_')[0].upper()
hpsuDict = {}

# read the translation file. if it doesn't exist, take the english one
command_translations_hpsu = '%s/commands_hpsu_%s.csv' % (self.pathCOMMANDS, LANG_CODE)
if not os.path.isfile(command_translations_hpsu):
command_translations_hpsu = '%s/commands_hpsu_%s.csv' % (self.pathCOMMANDS, "EN")
self.logger.info("loading command traslations file: "+command_translations_hpsu)
self.logger.info("HPSU %s, loading command traslations file: %s" % (cmd, command_translations_hpsu))
# check, if commands are json or csv
# read all known commands
with open(command_translations_hpsu, 'rU',encoding='utf-8') as csvfile:
Expand All @@ -63,7 +63,7 @@ def __init__(self, logger=None, driver=None, port=None, cmd=None, lg_code=None):

# read all known commands
command_details_hpsu = '%s/commands_hpsu.json' % self.pathCOMMANDS
self.logger.info("loading command details file: "+command_details_hpsu)
self.logger.info("HPSU %s, loading command details file: %s" % (cmd, command_details_hpsu))
with open(command_details_hpsu, 'rU',encoding='utf-8') as jsonfile:
self.all_commands = json.load(jsonfile)
self.command_dict=self.all_commands["commands"]
Expand Down Expand Up @@ -220,6 +220,8 @@ def umConversion(self, cmd, response, verbose):
resp = str(response["resp"])
else:
resp = str(response["resp"])
# TODO replaces resp with the decoded value, major breaking change to be discussed
# meanwhile, a 'desc' field is added to the output json
#if cmd["value_code"]:
# resp=cmd["value_code"][resp]
return resp
16 changes: 9 additions & 7 deletions HPSU/canpi.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class CanPI(object):
def __init__(self, hpsu=None):
self.hpsu = hpsu
try:
# TODO evaluate can.ThreadSafeBus
self.bus = can.interface.Bus(channel='can0', bustype='socketcan_native')
except Exception:
self.hpsu.logger.exception('Error opening bus can0')
Expand Down Expand Up @@ -77,7 +78,7 @@ def sendCommandWithID(self, cmd, setValue=None, priority=1):
command = command+" %02X %02X" % (setValue >> 8, setValue & 0xff)
if cmd["type"] == "value":
setValue = int(setValue)
command = command+" 00 %02X" % (setValue)
command = command+" %02X %02X" % (setValue >> 8, setValue & 0xff)

msg_data = [int(r, 16) for r in command.split(" ")]
notTimeout = True
Expand All @@ -86,6 +87,7 @@ def sendCommandWithID(self, cmd, setValue=None, priority=1):
try:
msg = can.Message(arbitration_id=receiver_id, data=msg_data, extended_id=False, dlc=7)
self.bus.send(msg)
self.hpsu.logger.debug("CanPI, %s sent: %s" % (cmd['name'], msg))

except Exception:
self.hpsu.logger.exception('Error sending msg')
Expand All @@ -107,17 +109,17 @@ def sendCommandWithID(self, cmd, setValue=None, priority=1):
if (msg_data[2] == 0xfa and msg_data[3] == rcBUS.data[3] and msg_data[4] == rcBUS.data[4]) or (msg_data[2] != 0xfa and msg_data[2] == rcBUS.data[2]):
rc = "%02X %02X %02X %02X %02X %02X %02X" % (rcBUS.data[0], rcBUS.data[1], rcBUS.data[2], rcBUS.data[3], rcBUS.data[4], rcBUS.data[5], rcBUS.data[6])
notTimeout = False
#print("got: " + str(rc))
self.hpsu.logger.debug("CanPI %s, got: %s" % (cmd['name'], str(rc)))
else:
self.hpsu.logger.error('SEND:%s' % (str(msg_data)))
self.hpsu.logger.error('RECV:%s' % (str(rcBUS.data)))
self.hpsu.logger.warning('CanPI %s, SEND: %s' % (cmd['name'], str(msg_data)))
self.hpsu.logger.warning('CanPI %s, RECV: %s' % (cmd['name'], str(rcBUS.data)))
else:
self.hpsu.logger.error('Not aquired bus')
self.hpsu.logger.warning('CanPI %s, Not aquired bus' % cmd['name'])

if notTimeout:
self.hpsu.logger.warning('msg not sync, retry: %s' % i)
self.hpsu.logger.warning('CanPI %s, msg not sync, retry: %s' % (cmd['name'], i))
if i >= self.retry:
self.hpsu.logger.error('msg not sync, timeout')
self.hpsu.logger.error('CanPI %s, msg not sync, timeout' % cmd['name'])
notTimeout = False
rc = "KO"

Expand Down
2 changes: 0 additions & 2 deletions HPSU/cantcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
import uuid
import json

SocketPort = 7060

class CanTCP(object):
sock = None
hpsu = None
Expand Down
82 changes: 26 additions & 56 deletions HPSU/plugins/mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,65 +33,41 @@ def __init__(self, hpsu=None, logger=None, config_file=None):
else:
sys.exit(9)

# MQTT hostname or IP
if self.config.has_option('MQTT', 'BROKER'):
self.brokerhost = self.config['MQTT']['BROKER']
else:
self.brokerhost = 'localhost'

# MQTT broker port
if self.config.has_option('MQTT', 'PORT'):
self.brokerport = int(self.config['MQTT']['PORT'])
else:
self.brokerport = 1883

# MQTT client name
if self.config.has_option('MQTT', 'CLIENTNAME'):
self.clientname = self.config['MQTT']['CLIENTNAME']
else:
self.clientname = 'rotex'
# MQTT Username
if self.config.has_option('MQTT', 'USERNAME'):
self.username = self.config['MQTT']['USERNAME']
else:
self.username = None
self.hpsu.logger.error("Username not set!!!!!")

#MQTT Password
if self.config.has_option('MQTT', "PASSWORD"):
self.password = self.config['MQTT']['PASSWORD']
else:
self.password="None"

#MQTT Prefix
if self.config.has_option('MQTT', "PREFIX"):
self.prefix = self.config['MQTT']['PREFIX']
else:
self.prefix = ""

#MQTT QOS
if self.config.has_option('MQTT', "QOS"):
self.qos = self.config['MQTT']['QOS']
else:
self.qos = "0"

# object to store entire MQTT config section
self.mqtt_config = self.config['MQTT']
self.brokerhost = self.mqtt_config.get('BROKER', 'localhost')
self.brokerport = self.mqtt_config.getint('PORT', 1883)
self.clientname = self.mqtt_config.get('CLIENTNAME', 'rotex')
self.username = self.mqtt_config.get('USERNAME', None)
if self.username is None:
self.logger.error("Username not set!!!!!")
self.password = self.mqtt_config.get('PASSWORD', "NoPasswordSpecified")
self.prefix = self.mqtt_config.get('PREFIX', "")
self.qos = self.mqtt_config.getint('QOS', 0)
# every other value implies false
self.retain = self.mqtt_config.get('RETAIN', "NOT TRUE") == "True"
# every other value implies false
self.addtimestamp = self.mqtt_config.get('ADDTIMESTAMP', "NOT TRUE") == "True"

self.logger.info("configuration parsing complete")

# no need to create a different client name every time, because it only publish
self.logger.info("creating new mqtt client instance: " + self.clientname)
self.client=mqtt.Client(self.clientname)
#self.client.on_publish = self.on_publish()
self.client.on_publish = self.on_publish
if self.username:
self.client.username_pw_set(self.username, password=self.password)
self.client.enable_logger()



#def on_publish(self,client,userdata,mid):
# self.hpsu.logger.debug("data published, mid: " + str(mid) + "\n")
# pass

def on_publish(self,client,userdata,mid):
self.hpsu.logger.debug("mqtt output plugin data published, mid: " + str(mid))

def pushValues(self, vars=None):

#self.msgs=[]
for r in vars:
self.logger.info("connecting to broker: " + self.brokerhost + ", port: " + str(self.brokerport))
self.client.connect(self.brokerhost, port=self.brokerport)
msgs=[]
if self.prefix:
Expand All @@ -101,10 +77,4 @@ def pushValues(self, vars=None):
ret=self.client.publish(r['name'],payload=r['resp'], qos=int(self.qos))
topic=r['name']
msg={'topic':topic,'payload':r['resp'], 'qos':self.qos, 'retain':False}
self.client.disconnect()






self.client.disconnect()
2 changes: 1 addition & 1 deletion HPSU/plugins/mysql.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def __init__(self, hpsu=None, logger=None, config_file=None, config=None):
if db_config.has_option('MYSQL','DB_USER'):
db_user=db_config['MYSQL']['DB_USER']
else:
self.hpsu.logger.error(("No database user defined in config file.")
self.hpsu.logger.error("No database user defined in config file.")
sys.exit(9)

if db_config.has_option('MYSQL','DB_PASSWORD'):
Expand Down
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,45 @@ The pyHPSUD.py is started via systemd:
root@rotex:# systemctl enable hpsud.service
root@rotex:# systemctl start hpsud.service

4. MQTT Daemon mode
pyHPSU starts in daemon mode, it subscribe an MQTT topic and listen forever waiting for commands.
MQTT coordinates are specified through configuration file: the same property used by mqtt output plugin plus additional COMMANDTOPIC and STATUSTOPIC.
The daemon subscribe to the topic
` PREFIX / COMMANDTOPIC / +`
and publish to the topic
` PREFIX / <hpsu-command-name>`
publishing to COMMANDTOPIC with value '' or 'read' results in property red from hpsu and published to mqtt (same topics used by mqtt output plugin)
publishing to COMMANDTOPIC with another value results in pyHPSU trying to change that value on specified hpsu property and than re-reading the same property and publishing the obtained value
```
e.g.
configuration file (e.g. /etc/pyHPSU/pyhpsu.conf)
...
[MQTT]
BROKER = 192.168.1.94
PREFIX = myhpsu
COMMANDTOPIC = command
...
root@rotex:# pyHPSU.py --mqtt_daemon
user@anothersystem:# mosquitto_pub -h 192.168.1.94 -t "myhpsu/command/t_dhw" -m read
publish the current value of t_dhw red from hpsu into the following topic
myhpsu/status/t_dhw
e.g.
(with same config)
root@rotex:# pyHPSU.py --mqtt_daemon -a -o mqtt
user@anothersystem:# mosquitto_pub -h 192.168.1.94 -t "myhpsu/command/t_flow_day" -m 29
set the parameter t_flow_day to 29°C, meanwhile pyHPSU is running in automatic mode and publishing periodically to the appopriate mqtt topics
myhpsu/status/t_dhw
```

Now, you can query multiple values or run multiple pyHPSU.py processes. Simply set as driver HPSUD ("CANTCP") via commandline or the config file (PYHPSU section)
i.e. root@rotex:# pyHPSU.py -d HPSUD -c t_dhw_setpoint1

Loading

0 comments on commit 225d612

Please sign in to comment.