├── .gitignore ├── .vscode └── settings.json ├── HPSU ├── HPSU.py ├── __init__.py ├── canelm327.py ├── canemu.py ├── canpi.py ├── cantcp.py └── plugins │ ├── __init__.py │ ├── emoncms.py │ ├── fhem.py │ ├── homematic.py │ ├── influxdb.py │ ├── mqtt.py │ ├── mysql.py │ ├── openhab.py │ └── pdf.py ├── README.md ├── comandi_rotex_hpsu_elm327.xlsm ├── contrib ├── README.md ├── capture-publish │ ├── hpsu.fast.service │ ├── hpsu.fast.sh │ ├── hpsu.fast.timer │ ├── hpsu.listener.service │ ├── hpsu.listener.sh │ ├── hpsu.medium.service │ ├── hpsu.medium.sh │ ├── hpsu.medium.timer │ ├── hpsu.slow.service │ ├── hpsu.slow.sh │ ├── hpsu.slow.timer │ └── pyListener.py ├── control │ ├── Chrono-Thermostat │ │ ├── README.md │ │ ├── pyTermostato.py │ │ ├── termostato.service │ │ ├── termostato.sh │ │ └── termostato.timer │ ├── Flow-Control │ │ ├── README.md │ │ ├── mandata.service │ │ ├── mandata.sh │ │ └── pyMandata.py │ ├── README.md │ └── Setpoint-Mode │ │ ├── README.md │ │ ├── crontab-sample │ │ ├── set_IsteresiACS.py │ │ ├── set_T-ACS1.py │ │ ├── set_T-Ambiente1.py │ │ ├── set_T-ImpRefrig.py │ │ ├── setmode_Estate.py │ │ ├── setmode_Raffrescare.py │ │ └── setmode_Riscaldare.py └── hpsud_service_sample.7z ├── etc └── pyHPSU │ ├── commands_hpsu.json │ ├── commands_hpsu_DE.csv │ ├── commands_hpsu_EN.csv │ ├── commands_hpsu_IT.csv │ └── pyhpsu.conf ├── install.sh ├── pyHPSU.py ├── pyHPSUd.py ├── resources ├── pyHPSU-logo.jpg └── pyHPSU-logo.png └── systemd ├── hpsu.service └── hpsud.service /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.pyc 3 | install_pyHPSU 4 | install 5 | .vscode/settings.json 6 | .vscode/launch.json -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.pythonPath": "/usr/bin/python3" 3 | } -------------------------------------------------------------------------------- /HPSU/HPSU.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import platform 4 | import sys 5 | from HPSU.canelm327 import CanELM327 6 | from HPSU.canemu import CanEMU 7 | from HPSU.canpi import CanPI 8 | from HPSU.cantcp import CanTCP 9 | import platform 10 | import datetime 11 | import locale 12 | import sys 13 | import csv 14 | import json 15 | import os.path 16 | import time 17 | 18 | class HPSU(object): 19 | commands = [] 20 | listCommands = [] 21 | UM_DEGREE = "deg" 22 | UM_BOOLEAN = "bool" 23 | UM_PERCENT = "percent" 24 | UM_INT = "int" 25 | UM_BAR = "bar" 26 | UM_HOUR = "hour" 27 | driver = None 28 | 29 | pathCOMMANDS = "/etc/pyHPSU" 30 | 31 | def __init__(self, logger=None, driver=None, port=None, cmd=None, lg_code=None): 32 | self.can = None 33 | self.commands = [] # data for all commands requested 34 | self.listCommands = [] # all usable commands from csv 35 | self.logger = logger 36 | self.command_dict={} 37 | self.backup_commands=[] 38 | 39 | listCmd = [r.split(":")[0] for r in cmd] 40 | 41 | if not self.listCommands: #if we don't get a dict with commands 42 | 43 | # get language, if non given, take it from the system 44 | LANG_CODE = lg_code.upper()[0:2] if lg_code else locale.getdefaultlocale()[0].split('_')[0].upper() 45 | hpsuDict = {} 46 | 47 | # read the translation file. if it doesn't exist, take the english one 48 | commands_hpsu = '%s/commands_hpsu_%s.csv' % (self.pathCOMMANDS, LANG_CODE) 49 | if not os.path.isfile(commands_hpsu): 50 | commands_hpsu = '%s/commands_hpsu_%s.csv' % (self.pathCOMMANDS, "EN") 51 | # check, if commands are json or csv 52 | # read all known commands 53 | with open(commands_hpsu, 'rU',encoding='utf-8') as csvfile: 54 | pyHPSUCSV = csv.reader(csvfile, delimiter=';', quotechar='"') 55 | next(pyHPSUCSV, None) # skip the header 56 | for row in pyHPSUCSV: 57 | name = row[0] 58 | label = row[1] 59 | desc = row[2] 60 | hpsuDict.update({name:{"label":label, "desc":desc}}) 61 | 62 | # read all known commands 63 | 64 | with open('%s/commands_hpsu.json' % self.pathCOMMANDS, 'rU',encoding='utf-8') as jsonfile: 65 | self.all_commands = json.load(jsonfile) 66 | self.command_dict=self.all_commands["commands"] 67 | for single_command in self.command_dict: 68 | if self.command_dict[single_command]["name"] in hpsuDict: 69 | self.command_dict[single_command].update({ "label" : hpsuDict[self.command_dict[single_command]["name"]]["label"], "desc" : hpsuDict[self.command_dict[single_command]["name"]]["desc"]}) 70 | if (single_command in listCmd) or (len(listCmd) == 0): 71 | self.commands.append(self.command_dict[single_command]) 72 | if (self.command_dict[single_command]["writable"]=="true"): 73 | self.backup_commands.append(self.command_dict[single_command]["name"]) 74 | 75 | self.driver = driver 76 | if self.driver == "ELM327": 77 | self.can = CanELM327(self) 78 | elif self.driver == "EMU": 79 | self.can = CanEMU(self) 80 | elif self.driver == "PYCAN": 81 | self.can = CanPI(self) 82 | elif self.driver == "HPSUD": 83 | self.can = CanTCP(self) 84 | else: 85 | print("Error selecting driver %s" % self.driver) 86 | sys.exit(9) 87 | 88 | self.initInterface(port) 89 | 90 | def printd(self, level, msg): 91 | if self.logger: 92 | if level == 'warning': 93 | self.logger.warning(msg) 94 | elif level == 'error': 95 | self.logger.error(msg) 96 | elif level == 'info': 97 | self.logger.info(msg) 98 | elif level == 'exception': 99 | self.logger.exception(msg) 100 | else: 101 | if self.driver != "HPSUD": 102 | print("%s - %s" % (level, msg)) 103 | 104 | def sendCommandWithParse(self, cmd, setValue=None, priority=1): 105 | response = None 106 | verbose = "1" 107 | i = 1 108 | 109 | while i <= 3: 110 | rc = self.sendCommand(cmd, setValue=setValue, priority=priority) 111 | if rc != "KO": 112 | i = 4 113 | if not setValue: 114 | response = self.parseCommand(cmd=cmd, response=rc, verbose=verbose)["resp"] 115 | else: 116 | response = "" 117 | else: 118 | i += 1 119 | time.sleep(2.0) 120 | return response 121 | 122 | def getParameterValue(self, parameter, priority=1): 123 | response = None 124 | cmd = None 125 | for c in self.commands: 126 | if c["name"] == parameter: 127 | cmd = c 128 | if cmd: 129 | response = self.sendCommandWithParse(cmd=cmd, priority=priority) 130 | 131 | return response 132 | 133 | def setParameterValue(self, parameter, setValue, priority=1): 134 | response = None 135 | cmd = None 136 | for c in self.commands: 137 | if c["name"] == parameter: 138 | cmd = c 139 | 140 | if cmd: 141 | response = self.sendCommandWithParse(cmd=cmd, setValue=setValue, priority=priority) 142 | 143 | return response 144 | 145 | 146 | def initInterface(self, portstr=None, baudrate=38400, init=False): 147 | if self.driver == "ELM327": 148 | self.can.initInterface(portstr=portstr, baudrate=baudrate,init=True) 149 | elif self.driver == "HPSUD": 150 | self.can.initInterface() 151 | 152 | # funktion to set/read a value 153 | def sendCommand(self, cmd, setValue=None, priority=1): 154 | rc = self.can.sendCommandWithID(cmd=cmd, setValue=setValue, priority=priority) 155 | 156 | if rc not in ["KO", "OK"]: 157 | try: 158 | hexValues = [int(r, 16) for r in rc.split(" ")] 159 | except ValueError: 160 | return "KO" 161 | return rc 162 | 163 | def timestamp(self): 164 | epoch = datetime.datetime.utcfromtimestamp(0) 165 | return (datetime.datetime.now() - epoch).total_seconds() * 1000.0 166 | 167 | def toSigned(self, n, cmd): 168 | if cmd["unit"] == "deg": 169 | n = n & 0xffff 170 | return (n ^ 0x8000) - 0x8000 171 | else: 172 | return n 173 | 174 | 175 | def parseCommand(self, cmd, response, verbose): 176 | hexValues = [int(r, 16) for r in response.split(" ")] 177 | hexArray = response.split(" ") 178 | 179 | 180 | if cmd["type"] == "int": 181 | if hexValues[2] == 0xfa: 182 | resp = int(self.toSigned(hexValues[5], cmd) // float(cmd["divisor"])) 183 | else: 184 | resp = int(self.toSigned(hexValues[3], cmd) // float(cmd["divisor"])) 185 | 186 | elif cmd["type"] == "longint": 187 | if hexValues[2] == 0xfa: 188 | resp = int(self.toSigned(hexValues[5]*0x100+hexValues[6], cmd) // float(cmd["divisor"])) 189 | else: 190 | resp = int(self.toSigned(hexValues[3]*0x100+hexValues[4], cmd) // float(cmd["divisor"])) 191 | 192 | elif cmd["type"] == "float": 193 | if hexValues[2] == 0xfa: 194 | resp = self.toSigned(hexValues[5]*0x100+hexValues[6], cmd) / float(cmd["divisor"]) 195 | else: 196 | resp = self.toSigned(hexValues[3]*0x100+hexValues[4], cmd) / float(cmd["divisor"]) 197 | elif cmd["type"] == "value": 198 | if hexValues[2] == 0xfa: 199 | resp = int(str(hexArray[5]) + str(hexArray[6]),16) // int(cmd["divisor"]) 200 | else: 201 | resp = int(str(hexArray[3]) + str(hexArray[4]),16) // int(cmd["divisor"]) 202 | 203 | if verbose == "2": 204 | timestamp = datetime.datetime.now().isoformat() 205 | else: 206 | if sys.version_info >= (3, 0): 207 | timestamp = datetime.datetime.now().timestamp() 208 | else: 209 | timestamp = self.timestamp() 210 | 211 | return {"resp":resp, "timestamp":timestamp} 212 | 213 | 214 | def umConversion(self, cmd, response, verbose): 215 | # convert into different units 216 | resp = response["resp"] 217 | 218 | if cmd["unit"] == HPSU.UM_DEGREE: 219 | resp = locale.format("%.2f", round(response["resp"], 2)) 220 | if verbose == "2": 221 | resp = "%s c" % resp 222 | elif cmd["unit"] == HPSU.UM_BOOLEAN: 223 | resp = int(response["resp"]) 224 | if verbose == "2": 225 | resp = "ON" if resp == 1 else "OFF" 226 | elif cmd["unit"] == HPSU.UM_PERCENT: 227 | resp = int(response["resp"]) 228 | if verbose == "2": 229 | resp = "%s%%" % int(response["resp"]) 230 | elif cmd["unit"] == HPSU.UM_INT: 231 | resp = str(response["resp"]) 232 | else: 233 | resp = str(response["resp"]) 234 | #if cmd["value_code"]: 235 | # resp=cmd["value_code"][resp] 236 | return resp 237 | -------------------------------------------------------------------------------- /HPSU/__init__.py: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /HPSU/canelm327.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # v 0.0.1 by Vanni Brutto (Zanac) 4 | 5 | import serial 6 | import sys 7 | import time 8 | 9 | class CanELM327(object): 10 | portstr = None 11 | hpsu = None 12 | def __init__(self, hpsu=None): 13 | self.hpsu = hpsu 14 | 15 | def resetInterface(self): 16 | self.ser.flushInput() #flush input buffer, discarding all its contents 17 | self.ser.flushOutput() #flush output buffer, aborting current output and discard all that is in buffer 18 | try: 19 | self.ser.close() 20 | except: 21 | pass 22 | self.initInterface(self.portstr, 38400, True) 23 | 24 | def initInterface(self, portstr=None, baudrate=38400, init=False): 25 | self.portstr = portstr 26 | try: 27 | self.ser = serial.Serial(portstr, baudrate, timeout=1) 28 | self.ser.close() 29 | self.ser.open() 30 | self.ser.flushInput() #flush input buffer, discarding all its contents 31 | self.ser.flushOutput() #flush output buffer, aborting current output and discard all that is in buffer 32 | except serial.SerialException: 33 | self.hpsu.printd("error", "Error opening serial %s" % portstr) 34 | sys.exit(9) 35 | 36 | if init: 37 | rc = self.sendCommand("ATE0") 38 | 39 | rc = self.sendCommand("AT PP 2F ON") 40 | """ if rc != "OK": 41 | self.hpsu.printd("error", "Error sending AT PP 2F ON (rc:%s)" % rc) 42 | sys.exit(9) """ 43 | count_1=0 44 | while rc != "OK": 45 | if count_1==15: 46 | self.hpsu.printd("error", "can adapter not responding: (rc:%s)" % rc) 47 | sys.exit(9) 48 | else: 49 | self.hpsu.printd("error", "Error sending AT PP 2F ON (rc:%s)" % rc) 50 | count_1+=1 51 | time.sleep(1) 52 | 53 | """rc = self.sendCommand("AT D") 54 | if rc != "OK": 55 | print "Error sending AT D (rc:%s)" % rc 56 | sys.exit(9)""" 57 | 58 | rc = self.sendCommand("AT SP C") 59 | count_2=0 60 | while rc != "OK": 61 | if count_2==15: 62 | self.hpsu.printd("error", "can adapter not responding: (rc:%s)" % rc) 63 | sys.exit(9) 64 | else: 65 | self.hpsu.printd("error", "Error sending AT SP C (rc:%s)" % rc) 66 | count_2+=1 67 | time.sleep(1) 68 | 69 | def sendCommand(self, cmd, setValue=None, type=None): 70 | command = "" 71 | 72 | if setValue and type: 73 | command = cmd[:1] + '2' + cmd[2:] 74 | if command[6:8] != "FA": 75 | command = command[:3]+"00 FA"+command[2:8] 76 | command = command[:14] 77 | 78 | if type == "int": 79 | setValue = int(setValue) 80 | command = command+" %02X 00" % (setValue) 81 | if type == "longint": 82 | setValue = int(setValue) 83 | command = command+" 00 %02X" % (setValue) 84 | if type == "float": 85 | setValue = int(setValue) 86 | if setValue < 0: 87 | setValue = 0x10000+setValue 88 | command = command+" %02X %02X" % (setValue >> 8, setValue & 0xff) 89 | if type == "value": 90 | setValue = int(setValue) 91 | command = command+" 00 %02X" % (setValue) 92 | 93 | #self.hpsu.printd("info", "cmd: %s cmdMod: %s" % (cmd, command)) 94 | cmd = command 95 | 96 | self.ser.write(bytes(str("%s\r\n" % cmd).encode('utf-8'))) 97 | time.sleep(50.0 / 1000.0) 98 | if setValue and type: 99 | return "OK" 100 | 101 | ser_read = self.ser.read(size=100) 102 | rc = ser_read.decode('utf-8')[:-3] 103 | rc = rc.replace("\r", "").replace("\n", "").strip() 104 | return rc 105 | 106 | def sendCommandWithID(self, cmd, setValue=None, priority=1): 107 | if setValue: 108 | rc = self.sendCommand("ATSH680") 109 | else: 110 | rc = self.sendCommand("ATSH"+cmd["id"]) 111 | if rc != "OK": 112 | self.resetInterface() 113 | self.hpsu.printd('warning', "Error setting ID %s (rc:%s)" % (cmd["id"], rc)) 114 | return "KO" 115 | 116 | rc = self.sendCommand(cmd["command"], setValue, cmd["type"]) 117 | if setValue: 118 | return rc 119 | 120 | if rc[0:1] != cmd["command"][0:1]: 121 | self.resetInterface() 122 | self.hpsu.printd('warning', 'sending cmd %s (rc:%s)' % (cmd["command"], rc)) 123 | return "KO" 124 | 125 | return rc 126 | 127 | def getInterface(self): 128 | return self.sendCommand("ATI") 129 | -------------------------------------------------------------------------------- /HPSU/canemu.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # v 0.0.1 by Vanni Brutto (Zanac) 4 | import sys 5 | import time 6 | 7 | class CanEMU(object): 8 | hspu = None 9 | def __init__(self, hpsu=None): 10 | self.hpsu = hpsu 11 | 12 | def eprint(self, *args): 13 | sys.stderr.write(' '.join(map(str,args)) + '\n') 14 | 15 | def sendCommandWithID(self, cmd, setValue=None, priority=1): 16 | arrResponse = [ 17 | {"name":"t_hs","resp":"32 10 FA 01 D6 01 0C"}, 18 | {"name":"t_hs_set","resp":"32 10 02 01 01 00 00"}, 19 | {"name":"water_pressure","resp":"32 10 FA C0 B4 00 22"}, 20 | {"name":"t_ext","resp":"62 10 FA 0A 0C FF 69"}, 21 | {"name":"t_dhw","resp":"32 10 0E 01 B1 00 00"}, 22 | {"name":"t_dhw_set","resp":"32 10 03 01 CC 00 00"}, 23 | {"name":"t_return","resp":"32 10 16 00 DF 00 00"}, 24 | {"name":"flow_rate","resp":"32 10 FA 01 DA 05 70"}, 25 | {"name":"t_hc","resp":"22 0A 0F 00 EB 00 00"}, 26 | {"name":"t_hc_set","resp":"62 10 04 01 01 00 00"}, 27 | {"name":"status_pump","resp":"32 10 FA 0A 8C 00 01"}, 28 | {"name":"runtime_comp","resp":"32 10 FA 06 A5 01 98"}, 29 | {"name":"runtime_pump","resp":"32 10 FA 06 A4 02 36"}, 30 | {"name":"posmix","resp":"32 10 FA 06 9B 00 00"}, 31 | {"name":"qboh","resp":"32 10 FA 09 1C 00 18"}, 32 | {"name":"qchhp","resp":"32 10 FA 09 20 00 04"}, 33 | {"name":"qsc","resp":"32 10 FA 06 A6 00 00"}, 34 | {"name":"qch","resp":"32 10 FA 06 A7 08 AF"}, 35 | {"name":"qwp","resp":"32 10 FA 09 30 0A 13"}, 36 | {"name":"qdhw","resp":"32 10 FA 09 2C 01 7B"}, 37 | {"name":"sw_vers_01","resp":"32 10 FA 01 99 01 6E"}, 38 | {"name":"sw_vers_02","resp":"32 10 FA C0 B4 00 22"}, 39 | {"name":"sw_vers_03","resp":"32 10 FA 02 4B 20 41"}, 40 | {"name":"mode_01","resp":"32 10 FA 01 12 03 00"}, 41 | {"name":"tvbh2","resp":"22 0A FA C1 02 01 3B"}, 42 | {"name":"tliq2","resp":"22 0A FA C1 03 01 36"}, 43 | {"name":"tr2","resp":"22 0A FA C1 04 00 FA"}, 44 | {"name":"ta2","resp":"22 0A FA C1 05 ff 4B"}, 45 | {"name":"tdhw2","resp":"22 0A FA C1 06 01 C3"}, 46 | {"name":"quiet","resp":"22 0A FA C1 07 00 00"}, 47 | {"name":"mode","resp":"22 0A FA C0 F6 00 01"}, 48 | {"name":"pump","resp":"22 0A FA C0 F7 00 4C"}, 49 | {"name":"ext","resp":"22 0A FA C0 F8 00 00"}, 50 | {"name":"ehs","resp":"22 0A FA C0 F9 00 00"}, 51 | {"name":"rt","resp":"22 0A FA C0 FA 00 01"}, 52 | {"name":"bpv","resp":"22 0A FA C0 FB 00 00"}, 53 | {"name":"t_dhw_setpoint1","resp":"31 00 13 01 B1 00 00"}, 54 | {"name":"hyst_hp","resp":"31 00 FA 06 91 05 00"}, 55 | {"name":"t_room1_setpoint","resp":"32 10 16 00 DF 00 00"}] 56 | 57 | if cmd["name"] == "runtime_pump": 58 | #self.eprint("Error sending %s" % (cmd["name"])) 59 | self.hpsu.printd('warning', 'sending cmd %s (rc:%s)' % (cmd["name"], "ko")) 60 | return "KO" 61 | 62 | #time.sleep(2.0) 63 | for r in arrResponse: 64 | if r["name"] == cmd["name"]: 65 | command = cmd["command"] 66 | if setValue: 67 | command = command[:1] + '2' + command[2:] 68 | if command[6:8] != "FA": 69 | command = command[:3]+"00 FA"+command[2:8] 70 | command = command[:14] 71 | if cmd["unit"] == "d": 72 | setValue = int(setValue) 73 | if setValue < 0: 74 | setValue = 0x10000+setValue 75 | command = command+" %02X %02X" % (setValue >> 8, setValue & 0xff) 76 | print(command) 77 | if cmd["unit"] == "i": 78 | setValue = int(setValue) 79 | command = command+" %02X 00" % (setValue) 80 | return "OK" 81 | 82 | return r["resp"] 83 | 84 | return "KO" 85 | -------------------------------------------------------------------------------- /HPSU/canpi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # v 0.0.3 by Vanni Brutto (Zanac) 4 | 5 | import sys 6 | import getopt 7 | import time 8 | import configparser 9 | import logging 10 | try: 11 | import can 12 | except Exception: 13 | pass 14 | 15 | class CanPI(object): 16 | hpsu = None 17 | timeout = None 18 | retry = None 19 | def __init__(self, hpsu=None): 20 | self.hpsu = hpsu 21 | try: 22 | self.bus = can.interface.Bus(channel='can0', bustype='socketcan_native') 23 | except Exception: 24 | self.hpsu.printd('exception', 'Error opening bus can0') 25 | sys.exit(9) 26 | 27 | config = configparser.ConfigParser() 28 | iniFile = '%s/%s.conf' % (self.hpsu.pathCOMMANDS, "pyhpsu") 29 | config.read(iniFile) 30 | self.timeout = float(self.get_with_default(config=config, section="CANPI", name="timeout", default=0.05)) 31 | self.retry = float(self.get_with_default(config=config, section="CANPI", name="retry", default=15)) 32 | 33 | 34 | def get_with_default(self, config, section, name, default): 35 | if "config" not in config.sections(): 36 | return default 37 | 38 | if config.has_option(section,name): 39 | return config.get(section,name) 40 | else: 41 | return default 42 | 43 | def __del__(self): 44 | pass 45 | """try: 46 | self.bus.shutdown() 47 | except Exception: 48 | self.hpsu.printd('exception', 'Error shutdown canbus')""" 49 | 50 | def sendCommandWithID(self, cmd, setValue=None, priority=1): 51 | if setValue: 52 | receiver_id = 0x680 53 | else: 54 | receiver_id = int(cmd["id"], 16) 55 | command = cmd["command"] 56 | 57 | if setValue: 58 | command = command[:1] + '2' + command[2:] 59 | if command[6:8] != "FA": 60 | command = command[:3]+"00 FA"+command[2:8] 61 | command = command[:14] 62 | """ if cmd["unit"] == "deg": 63 | setValue = int(setValue) 64 | if setValue < 0: 65 | setValue = 0x10000+setValue 66 | command = command+" %02X %02X" % (setValue >> 8, setValue & 0xff)""" 67 | if cmd["type"] == "longint" : 68 | setValue = int(setValue) 69 | command = command+" 00 %02X" % (setValue) 70 | if cmd["type"] == "int": 71 | setValue = int(setValue) 72 | command = command+" %02X 00" % (setValue) 73 | if cmd["type"] == "float": 74 | setValue = int(setValue) 75 | if setValue < 0: 76 | setValue = 0x10000+setValue 77 | command = command+" %02X %02X" % (setValue >> 8, setValue & 0xff) 78 | if cmd["type"] == "value": 79 | setValue = int(setValue) 80 | command = command+" 00 %02X" % (setValue) 81 | 82 | msg_data = [int(r, 16) for r in command.split(" ")] 83 | notTimeout = True 84 | i = 0 85 | #print("sent: " + str(command)) 86 | try: 87 | msg = can.Message(arbitration_id=receiver_id, data=msg_data, extended_id=False, dlc=7) 88 | self.bus.send(msg) 89 | 90 | except Exception: 91 | self.hpsu.printd('exception', 'Error sending msg') 92 | 93 | if setValue: 94 | return "OK" 95 | 96 | while notTimeout: 97 | i += 1 98 | timeout = self.timeout 99 | rcBUS = None 100 | try: 101 | rcBUS = self.bus.recv(timeout) 102 | 103 | except Exception: 104 | self.hpsu.printd('exception', 'Error recv') 105 | 106 | if rcBUS: 107 | 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]): 108 | 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]) 109 | notTimeout = False 110 | #print("got: " + str(rc)) 111 | else: 112 | self.hpsu.printd('error', 'SEND:%s' % (str(msg_data))) 113 | self.hpsu.printd('error', 'RECV:%s' % (str(rcBUS.data))) 114 | else: 115 | self.hpsu.printd('error', 'Not aquired bus') 116 | 117 | if notTimeout: 118 | self.hpsu.printd('warning', 'msg not sync, retry: %s' % i) 119 | if i >= self.retry: 120 | self.hpsu.printd('error', 'msg not sync, timeout') 121 | notTimeout = False 122 | rc = "KO" 123 | 124 | return rc 125 | -------------------------------------------------------------------------------- /HPSU/cantcp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # v 0.0.1 by Vanni Brutto (Zanac) 4 | 5 | import sys 6 | import socket 7 | import time 8 | import pika 9 | import uuid 10 | import json 11 | 12 | SocketPort = 7060 13 | 14 | class CanTCP(object): 15 | sock = None 16 | hpsu = None 17 | 18 | def __init__(self, hpsu=None): 19 | self.hpsu = hpsu 20 | self.connection = pika.BlockingConnection(pika.ConnectionParameters( 21 | host='localhost')) 22 | 23 | self.channel = self.connection.channel() 24 | 25 | result = self.channel.queue_declare(exclusive=True, arguments={"x-max-priority":5}) 26 | self.callback_queue = result.method.queue 27 | 28 | #if type == "sync": 29 | self.channel.basic_consume(self.on_response, no_ack=True, 30 | queue=self.callback_queue) 31 | 32 | def on_response(self, ch, method, props, body): 33 | """print(body) 34 | print ("confronto") 35 | print(str(self.corr_id)) 36 | print(str(props.correlation_id))""" 37 | 38 | if self.corr_id == props.correlation_id: 39 | self.response = body 40 | #print("uguale") 41 | 42 | def initInterface(self): 43 | pass 44 | 45 | def sendCommandWithID(self, cmd, setValue=None, priority=1): 46 | if setValue: 47 | priority = 3 48 | self.response = None 49 | self.corr_id = str(uuid.uuid4()) 50 | #print("spedisco:"+str(self.corr_id)) 51 | dataSEND = {"name":cmd["name"], "value":setValue, "type":"sync"} 52 | self.channel.basic_publish(exchange='', 53 | routing_key='hpsu_queue', 54 | properties=pika.BasicProperties( 55 | reply_to = self.callback_queue, 56 | priority=priority, 57 | correlation_id = self.corr_id, 58 | ), 59 | body=str(json.dumps(dataSEND))) 60 | timeout = 0 61 | while self.response is None and timeout <= 200: 62 | time.sleep(0.1) 63 | self.connection.process_data_events() 64 | timeout += 1 65 | #print(str(timeout)) 66 | if timeout >= 200: 67 | self.response = b"KO" 68 | return self.response.decode('UTF-8') 69 | else: 70 | self.response = None 71 | self.corr_id = str(uuid.uuid4()) 72 | #print("spedisco:"+str(self.corr_id)) 73 | dataSEND = {"name":cmd["name"], "value":"", "type":"sync"} 74 | self.channel.basic_publish(exchange='', 75 | routing_key='hpsu_queue', 76 | properties=pika.BasicProperties( 77 | reply_to = self.callback_queue, 78 | priority=priority, 79 | correlation_id = self.corr_id, 80 | ), 81 | body=str(json.dumps(dataSEND))) 82 | timeout = 0 83 | while self.response is None and timeout <= 200: 84 | time.sleep(0.1) 85 | self.connection.process_data_events() 86 | timeout += 1 87 | #print(str(timeout)) 88 | if timeout >= 200: 89 | self.response = b"KO" 90 | return self.response.decode('UTF-8') 91 | 92 | -------------------------------------------------------------------------------- /HPSU/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /HPSU/plugins/emoncms.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import configparser 5 | import requests 6 | import sys 7 | import os 8 | 9 | # config inf conf_file (defaults): 10 | # [EMONCMS] 11 | # URL = https://emoncms.org 12 | # node_1 = t_hs, t_hs_setpoint 13 | # node_2 = qoh.... 14 | # ...... 15 | # ...... 16 | 17 | 18 | class export(): 19 | hpsu = None 20 | 21 | def get_with_default(self, config, section, name, default): 22 | if "config" not in config.sections(): 23 | return default 24 | 25 | if config.has_option(section,name): 26 | return config.get(section,name) 27 | else: 28 | return default 29 | 30 | def __init__(self, hpsu=None, logger=None, config_file=None): 31 | self.hpsu = hpsu 32 | self.logger = logger 33 | self.config_file = config_file 34 | self.config = configparser.ConfigParser() 35 | if os.path.isfile(self.config_file): 36 | self.config.read(self.config_file) 37 | else: 38 | sys.exit(9) 39 | 40 | # URL to emoncms server 41 | if self.config.has_option('EMONCMS', 'URL'): 42 | self.emonurl = self.config['EMONCMS']['URL'] 43 | else: 44 | self.emonurl = 'https://emoncms.org' 45 | 46 | # API-Key 47 | if self.config.has_option('EMONCMS', 'APIKEY'): 48 | self.emonkey = self.config['EMONCMS']['APIKEY'] 49 | else: 50 | self.emonkey = 'xxxxxxxxxx' 51 | 52 | self.listNodes = {} 53 | self.listCmd = [] 54 | options = self.config.options("EMONCMS") 55 | for option in options: 56 | if option.startswith("node_"): 57 | try: 58 | self.listNodes[option] = self.config.get("EMONCMS", option).split(',') 59 | self.listCmd.extend(self.listNodes[option]) 60 | 61 | for c in self.listNodes[option]: 62 | InCommand = True 63 | for j in self.hpsu.commands: 64 | if c == j["name"]: 65 | InCommand = False 66 | if InCommand: 67 | self.hpsu.printd("warning", "command %s defined in emoncms but not as commandline option" % c) 68 | 69 | except: 70 | self.listNodes[option] = None 71 | 72 | for r in self.hpsu.commands: 73 | if r["name"] not in self.listCmd: 74 | self.hpsu.printd("warning", "command %s defined as commandline option but not in emoncms" % r["name"]) 75 | 76 | def pushValues(self, vars): 77 | #if self.plugin == "EMONCMS": 78 | # timestamp = None 79 | 80 | # for node in self.listNodes: 81 | # Commented out...why are the first 5 characters are stripped? 82 | # nodeName = node[5:] 83 | timestamp = None 84 | for node in self.listNodes: 85 | nodeName = node 86 | varsDict = {} 87 | for r in vars: 88 | if not timestamp: 89 | timestamp = r["timestamp"] 90 | 91 | for r2 in self.listNodes[node]: 92 | if r2 == r["name"]: 93 | varsDict.update({r["name"]:r["resp"]}) 94 | if len(varsDict) > 0: 95 | varsTxt = str(varsDict).replace(" ", "") 96 | # _url = "https://emoncms.org/api/post?apikey=%s&time:%s&json=%s&node=%s" % (self.apikey, timestamp, varsTxt, nodeName) 97 | # _urlNoApi = "https://emoncms.org/api/post?apikey=%s&time:%s&json=%s&node=%s" % ('xxx', timestamp, varsTxt, nodeName) 98 | _url = "%s/input/post?apikey=%s&time:%s&json=%s&node=%s" % (self.emonurl, self.emonkey, timestamp, varsTxt, nodeName) 99 | _urlNoApi = "%s/input/post?apikey=%s&time:%s&json=%s&node=%s" % (self.emonurl, 'xxx', timestamp, varsTxt, nodeName) 100 | 101 | try: 102 | r = requests.get(_url, timeout=7) 103 | rc = r.text 104 | except (requests.exceptions.Timeout): 105 | rc = "ko" 106 | self.hpsu.printd("exception", "Connection timeout during get %s" % _urlNoApi) 107 | except (requests.exceptions.ConnectionError): 108 | self.hpsu.printd("exception", "Failed to establish a new connection to %s" % _urlNoApi) 109 | except Exception: 110 | rc = "ko" 111 | self.hpsu.printd("exception", "Exception on get %s" % _urlNoApi) 112 | 113 | return True -------------------------------------------------------------------------------- /HPSU/plugins/fhem.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | # config inf conf_file (defaults): 6 | # [FHEM] 7 | # METHOD = telnet 8 | # HOST = localhost 9 | # PORT = 7072 10 | # DEVICE = HPSU 11 | 12 | import socket 13 | import configparser 14 | import sys 15 | import os 16 | 17 | 18 | class export(): 19 | hpsu = None 20 | 21 | def __init__(self, hpsu=None, logger=None, config_file=None): 22 | self.hpsu = hpsu 23 | self.logger = logger 24 | self.config_file = config_file 25 | self.config = configparser.ConfigParser() 26 | if os.path.isfile(self.config_file): 27 | self.config.read(self.config_file) 28 | else: 29 | sys.exit(9) 30 | 31 | # fhem's telnet hostname 32 | if self.config.has_option('FHEM', 'HOST'): 33 | self.fhemhost = self.config['FHEM']['HOST'] 34 | else: 35 | self.fhemhost = 'localhost' 36 | 37 | # fhem's telnet port 38 | if self.config.has_option('FHEM', 'PORT'): 39 | self.fhemport = int(self.config['FHEM']['PORT']) 40 | else: 41 | self.fhemport = 7072 42 | 43 | # fhem's device name 44 | if self.config.has_option('FHEM', 'DEVICE'): 45 | self.fhemdevice = self.config['FHEM']['DEVICE'] 46 | else: 47 | self.fhemdevice = 'HPSU' 48 | 49 | # method to put the data 50 | if self.config.has_option('FHEM','METHOD'): 51 | self.method=self.config['FHEM']['METHOD'] 52 | else: 53 | self.method="telnet" 54 | 55 | def netcat(self, hostname, fhemport, content): 56 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 57 | s.connect((hostname, fhemport)) 58 | s.sendall((content).encode()) 59 | s.shutdown(socket.SHUT_WR) 60 | s.close() 61 | 62 | def pushValues(self, vars=None): 63 | if self.method == "telnet": 64 | for r in vars: 65 | # empty netcat string 66 | s = "" 67 | u = "" 68 | u += ("%s %s" % (r["name"], r["resp"])) 69 | s += 'setreading ' + self.fhemdevice + ' pyHPSU.' + u + '\n' 70 | s += "quit" 71 | self.netcat(self.fhemhost, self.fhemport, s) 72 | 73 | if __name__ == '__main__': 74 | app = fhem() 75 | 76 | app.exec_() 77 | -------------------------------------------------------------------------------- /HPSU/plugins/homematic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | # config inf conf_file (defaults): 6 | # [HOMEMATIC] 7 | # METHOD = xmlapi 8 | # HOST = HOSTNAME_OR_IP_CCU 9 | # PORT = 80 10 | # TOKEN = XML-API and call tokenregister.py. Copy the resulting token. 11 | 12 | import socket 13 | import configparser 14 | import sys 15 | import os 16 | import urllib.request 17 | 18 | 19 | class export(): 20 | hpsu = None 21 | 22 | def __init__(self, hpsu=None, logger=None, config_file=None): 23 | self.hpsu = hpsu 24 | self.logger = logger 25 | self.config_file = config_file 26 | self.config = configparser.ConfigParser() 27 | if os.path.isfile(self.config_file): 28 | self.config.read(self.config_file) 29 | else: 30 | sys.exit(9) 31 | # homematic's token 32 | if self.config.has_option('HOMEMATIC', 'TOKEN'): 33 | self.token = self.config['HOMEMATIC']['TOKEN'] 34 | else: 35 | self.token = '' 36 | 37 | # homematic's hostname or IP 38 | if self.config.has_option('HOMEMATIC', 'HOST'): 39 | self.homematichost = self.config['HOMEMATIC']['HOST'] 40 | else: 41 | self.homematichost = 'localhost' 42 | 43 | # homematic's port 44 | if self.config.has_option('HOMEMATIC', 'PORT'): 45 | self.homematicport = int(self.config['HOMEMATIC']['PORT']) 46 | else: 47 | self.homematicport = 80 48 | 49 | # method to put the data 50 | if self.config.has_option('HOMEMATIC','METHOD'): 51 | self.method=self.config['HOMEMATIC']['METHOD'] 52 | else: 53 | self.method="xmlapi" 54 | 55 | def xmlapi_send(self, url): 56 | self.url=url 57 | req=urllib.request.Request(self.url) 58 | try: 59 | urllib.request.urlopen(req) 60 | except urllib.error.URLError as e: 61 | rc = "ko" 62 | self.hpsu.printd("exception", "Error " + str(e.code) + ": " + str(e.reason)) 63 | 64 | def pushValues(self, vars=None): 65 | if self.method == "xmlapi": 66 | for r in vars: 67 | self.ISE_ID=self.config['HOMEMATIC'][r['name']] 68 | 69 | # The XML-API version >=2.0 requires an token like 'sdfhlskdjfng'. To add this token use the following line: 70 | 71 | self.url_string="http://" + str(self.homematichost) + ":" + str(self.homematicport) + "/config/xmlapi/statechange.cgi?sid=" + self.token + "&ise_id=" + self.ISE_ID + "&new_value=" + str(r['resp']) 72 | self.xmlapi_send(self.url_string) 73 | 74 | #if __name__ == '__main__': 75 | # app = homematic() 76 | 77 | # app.exec_() 78 | -------------------------------------------------------------------------------- /HPSU/plugins/influxdb.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | # config inf conf_file (defaults): 6 | # [INFLUXDB] 7 | # HOST = hostname_or_ip 8 | # PORT = 8086 9 | # DB_NAME = pyHPSU 10 | 11 | import configparser 12 | import requests 13 | import sys 14 | import os 15 | import datetime 16 | import influxdb 17 | 18 | 19 | class export(): 20 | hpsu = None 21 | 22 | def __init__(self, hpsu=None, logger=None, config_file=None): 23 | self.hpsu = hpsu 24 | self.logger = logger 25 | self.config_file = config_file 26 | self.config = configparser.ConfigParser() 27 | if os.path.isfile(self.config_file): 28 | self.config.read(self.config_file) 29 | else: 30 | sys.exit(9) 31 | 32 | # influxdb hostname or IP 33 | if self.config.has_option('INFLUXDB', 'HOST'): 34 | self.influxdbhost = self.config['INFLUXDB']['HOST'] 35 | else: 36 | self.influxdbhost = 'localhost' 37 | 38 | # influxdb port 39 | if self.config.has_option('INFLUXDB', 'PORT'): 40 | self.influxdbport = int(self.config['INFLUXDB']['PORT']) 41 | else: 42 | self.influxdbport = 8086 43 | 44 | # influxdb db name 45 | if self.config.has_option('INFLUXDB', 'DB_NAME'): 46 | self.influxdbname = self.config['INFLUXDB']['DB_NAME'] 47 | else: 48 | self.influxdbname = "pyHPSU" 49 | 50 | 51 | 52 | def pushValues(self, vars=None): 53 | self.current_time = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ') 54 | # create connection 55 | self.client = influxdb.InfluxDBClient(host=self.influxdbhost, port=self.influxdbport) 56 | # create database if it doesn't exist 57 | try: 58 | self.databases=self.client.get_list_database() 59 | db_found = False 60 | for db in self.databases: 61 | if db['name'] == self.influxdbname: 62 | db_found = True 63 | if not(db_found): 64 | self.client.create_database(self.influxdbname) 65 | 66 | except: 67 | rc = "ko" 68 | self.hpsu.printd("exception", "Error : Cannot connect to database") 69 | 70 | 71 | self.client.switch_database(self.influxdbname) 72 | 73 | for dict in vars: 74 | 75 | self.value_dict=[{ 76 | "measurement": "pyHPSU", 77 | "tags":{ 78 | }, 79 | "fields": { 80 | dict["name"] : dict["resp"] 81 | } 82 | } 83 | ] 84 | 85 | self.client.write_points(self.value_dict) 86 | 87 | 88 | 89 | #if __name__ == '__main__': 90 | # app = influxdb() 91 | 92 | # app.exec_() 93 | -------------------------------------------------------------------------------- /HPSU/plugins/mqtt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | # config inf conf_file (defaults): 6 | # [MQTT] 7 | # BROKER = localhost 8 | # PORT = 1883 9 | # USERNAME = 10 | # PASSWORD = 11 | # CLIENTNAME = rotex_hpsu 12 | # PREFIX = rotex 13 | 14 | import configparser 15 | import requests 16 | import sys 17 | import os 18 | import paho.mqtt.publish as publish 19 | import paho.mqtt.client as mqtt 20 | 21 | 22 | 23 | class export(): 24 | hpsu = None 25 | 26 | def __init__(self, hpsu=None, logger=None, config_file=None): 27 | self.hpsu = hpsu 28 | self.logger = logger 29 | self.config_file = config_file 30 | self.config = configparser.ConfigParser() 31 | if os.path.isfile(self.config_file): 32 | self.config.read(self.config_file) 33 | else: 34 | sys.exit(9) 35 | 36 | # MQTT hostname or IP 37 | if self.config.has_option('MQTT', 'BROKER'): 38 | self.brokerhost = self.config['MQTT']['BROKER'] 39 | else: 40 | self.brokerhost = 'localhost' 41 | 42 | # MQTT broker port 43 | if self.config.has_option('MQTT', 'PORT'): 44 | self.brokerport = int(self.config['MQTT']['PORT']) 45 | else: 46 | self.brokerport = 1883 47 | 48 | # MQTT client name 49 | if self.config.has_option('MQTT', 'CLIENTNAME'): 50 | self.clientname = self.config['MQTT']['CLIENTNAME'] 51 | else: 52 | self.clientname = 'rotex' 53 | # MQTT Username 54 | if self.config.has_option('MQTT', 'USERNAME'): 55 | self.username = self.config['MQTT']['USERNAME'] 56 | else: 57 | self.username = None 58 | print("Username not set!!!!!") 59 | 60 | #MQTT Password 61 | if self.config.has_option('MQTT', "PASSWORD"): 62 | self.password = self.config['MQTT']['PASSWORD'] 63 | else: 64 | self.password="None" 65 | 66 | #MQTT Prefix 67 | if self.config.has_option('MQTT', "PREFIX"): 68 | self.prefix = self.config['MQTT']['PREFIX'] 69 | else: 70 | self.prefix = "" 71 | 72 | #MQTT QOS 73 | if self.config.has_option('MQTT', "QOS"): 74 | self.qos = self.config['MQTT']['QOS'] 75 | else: 76 | self.qos = "0" 77 | 78 | self.client=mqtt.Client(self.clientname) 79 | #self.client.on_publish = self.on_publish() 80 | if self.username: 81 | self.client.username_pw_set(self.username, password=self.password) 82 | self.client.enable_logger() 83 | 84 | 85 | 86 | #def on_publish(self,client,userdata,mid): 87 | # print("data published, mid: " + str(mid) + "\n") 88 | # pass 89 | 90 | 91 | def pushValues(self, vars=None): 92 | 93 | #self.msgs=[] 94 | for r in vars: 95 | self.client.connect(self.brokerhost, port=self.brokerport) 96 | msgs=[] 97 | if self.prefix: 98 | ret=self.client.publish(self.prefix + "/" + r['name'],payload=r['resp'], qos=int(self.qos)) 99 | topic=self.prefix + "/" + r['name'] 100 | else: 101 | ret=self.client.publish(r['name'],payload=r['resp'], qos=int(self.qos)) 102 | topic=r['name'] 103 | msg={'topic':topic,'payload':r['resp'], 'qos':self.qos, 'retain':False} 104 | self.client.disconnect() 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /HPSU/plugins/mysql.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | 5 | # Entries in pyhpsu.conf 6 | # [MYSQL] 7 | # DB_HOST = localhost 8 | # DB_PORT = 3306 9 | # DB_NAME = HPSU 10 | # DB_USER = HPSU_USER 11 | # DB_PASSWORD = HPSU_PASSWORD 12 | 13 | import mysql.connector 14 | from mysql.connector import errorcode 15 | import configparser 16 | import sys 17 | import os 18 | from distutils.version import StrictVersion 19 | 20 | class db(): 21 | hpsu = None 22 | 23 | def __init__(self, hpsu=None, logger=None, config_file=None, config=None): 24 | self.hpsu = hpsu 25 | self.logger = logger 26 | self.config = config 27 | self.config_file=config_file 28 | self.db_version = None 29 | 30 | 31 | db_config = configparser.ConfigParser() 32 | if not self.config_file: 33 | self.config_file="/etc/pyHPSU/pyHPSU.conf" 34 | 35 | if os.path.isfile(self.config_file): 36 | db_config.read(self.config_file) 37 | else: 38 | sys.exit(9) 39 | if db_config.has_option('MYSQL','DB_HOST'): 40 | db_host=db_config['MYSQL']['DB_HOST'] 41 | else: 42 | db_host="localhost" 43 | 44 | if db_config.has_option('MYSQL','DB_PORT'): 45 | db_port=db_config['MYSQL']['DB_PORT'] 46 | else: 47 | db_port="3306" 48 | 49 | if db_config.has_option('MYSQL','DB_NAME'): 50 | db_name=db_config['MYSQL']['DB_NAME'] 51 | else: 52 | print("No database name defined in config file .") 53 | sys.exit(9) 54 | 55 | if db_config.has_option('MYSQL','DB_USER'): 56 | db_user=db_config['MYSQL']['DB_USER'] 57 | else: 58 | print("No database user defined in config file.") 59 | sys.exit(9) 60 | 61 | if db_config.has_option('MYSQL','DB_PASSWORD'): 62 | db_password=db_config['MYSQL']['DB_PASSWORD'] 63 | else: 64 | print("No password for the database user defined in config file") 65 | sys.exit(9) 66 | 67 | self.db_params={ 'host':db_host, 'port':db_port, 'user':db_user, 'password':db_password, 'database':db_name } 68 | 69 | try: 70 | self.db_conn= mysql.connector.connect(**self.db_params) 71 | except mysql.connector.Error as err: 72 | if err.errno == errorcode.ER_ACCESS_DENIED_ERROR: 73 | print("Username or password wrong") 74 | sys.exit(9) 75 | elif err.errno == errorcode.ER_BAD_DB_ERROR: 76 | print("Database does not exist") 77 | sys.exit(9) 78 | else: 79 | self.db_conn.close() 80 | #print("Closed") 81 | self.check_commands_db() 82 | 83 | def check_commands_db(self): 84 | 85 | # gets command from a dict HPSU created 86 | # Looks, if a version id could be found 87 | # if not or version_id is higher then in DB, commands are put into DB 88 | self.commands_file_version=self.hpsu.all_commands["version"] 89 | self.db_conn= mysql.connector.connect(**self.db_params) 90 | cursor=self.db_conn.cursor() 91 | cursor.execute("SELECT descr from commands WHERE name = 'version'") 92 | commands_db_version=cursor.fetchall() 93 | if commands_db_version: 94 | self.db_version=commands_db_version[0][0] 95 | 96 | # if no version info is found in DB 97 | if self.db_version: 98 | # update the version if a newer is available in commands_hpsu.csv 99 | if StrictVersion(self.commands_file_version) > StrictVersion(self.db_version): 100 | UpdateQuery="UPDATE commands SET descr='%s' WHERE name='%s'" % (self.hpsu.command_dict['version']['desc'],self.hpsu.command_dict['version']['name']) 101 | cursor.execute(UpdateQuery) 102 | # update all commands or insert the new ones 103 | self.update_db(cursor) 104 | 105 | else: 106 | # insert version info 107 | InsertQuery="INSERT INTO commands (name,descr) VALUES ('%s','%s')" % (self.hpsu.command_dict['version']['name'],self.hpsu.command_dict['version']['desc']) 108 | cursor.execute(InsertQuery) 109 | # and insert all the commands 110 | self.update_db(cursor) 111 | self.db_conn.commit() 112 | cursor.close() 113 | self.db_conn.close() 114 | 115 | def update_db(self,cursor): 116 | # and update all commands or insert the new ones 117 | for com in self.hpsu.command_dict: 118 | if com not in "version": 119 | n_name=self.hpsu.command_dict[com]['name'] 120 | n_desc=self.hpsu.command_dict[com]['desc'] 121 | n_command=self.hpsu.command_dict[com]['command'] 122 | n_label=self.hpsu.command_dict[com]['label'] 123 | n_receiver_id=self.hpsu.command_dict[com]['receiver_id'] 124 | n_um=self.hpsu.command_dict[com]['um'] 125 | n_div=self.hpsu.command_dict[com]['div'] 126 | n_flagRW=self.hpsu.command_dict[com]['flagRW'] 127 | # insert new commands 128 | UpdateQuery="INSERT INTO commands (name,descr,label,command,receiver_id,um,divisor,readwrite) VALUES ('%s','%s','%s','%s','%s','%s','%s','%s') on DUPLICATE KEY UPDATE descr='%s', command='%s', label='%s', receiver_id='%s', um='%s', divisor='%s', readwrite='%s'" % (n_name,n_desc,n_label,n_command,n_receiver_id,n_um,n_div,n_flagRW,n_desc,n_command,n_label,n_receiver_id,n_um,n_div,n_flagRW) 129 | cursor.execute(UpdateQuery) 130 | # insert table for each command 131 | TableQuery="CREATE TABLE IF NOT EXISTS `%s` (`id` int(20) NOT NULL PRIMARY KEY AUTO_INCREMENT,`value` float NOT NULL,`timestamp` varchar(20) COLLATE utf8_bin NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;" % (n_name) 132 | cursor.execute(TableQuery) 133 | 134 | def pushValues(self,vars=None): 135 | self.push_conn= mysql.connector.connect(**self.db_params) 136 | cursor=self.push_conn.cursor() 137 | for reply in vars: 138 | PushQuery="INSERT INTO commands (name, current_value, timestamp) VALUES ('%s', '%s','%s') on DUPLICATE KEY UPDATE current_value='%s', timestamp='%s'" % (reply['name'], reply['resp'], reply['timestamp'], reply['resp'], reply['timestamp']) 139 | cursor.execute(PushQuery) 140 | PushValueQuery="INSERT INTO %s (value,timestamp) VALUES ('%s','%s')" % (reply['name'],reply['resp'],reply['timestamp']) 141 | cursor.execute(PushValueQuery) 142 | self.push_conn.commit() 143 | cursor.close() 144 | self.push_conn.close() 145 | 146 | 147 | 148 | 149 | if __name__ == '__main__': 150 | app = db() 151 | 152 | app.exec_() -------------------------------------------------------------------------------- /HPSU/plugins/openhab.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | # config inf conf_file (defaults): 6 | # [OPENHAB] 7 | # HOST = hostname_or_ip 8 | # PORT = 8080 9 | # ITEMPREFIX = Rotex_ 10 | 11 | import configparser 12 | import requests 13 | import sys 14 | import os 15 | 16 | 17 | class export(): 18 | hpsu = None 19 | 20 | def __init__(self, hpsu=None, logger=None, config_file=None): 21 | self.hpsu = hpsu 22 | self.logger = logger 23 | self.config_file = config_file 24 | self.config = configparser.ConfigParser() 25 | if os.path.isfile(self.config_file): 26 | self.config.read(self.config_file) 27 | else: 28 | sys.exit(9) 29 | 30 | # openhab hostname or IP 31 | if self.config.has_option('OPENHAB', 'HOST'): 32 | self.openhabhost = self.config['OPENHAB']['HOST'] 33 | else: 34 | self.openhabhost = 'localhost' 35 | 36 | # openhab port 37 | if self.config.has_option('OPENHAB', 'PORT'): 38 | self.openhabport = int(self.config['OPENHAB']['PORT']) 39 | else: 40 | self.openhabport = 8080 41 | 42 | # openhab item name 43 | if self.config.has_option('OPENHAB', 'ITEMPREFIX'): 44 | self.openhabitemprefix = self.config['OPENHAB']['ITEMPREFIX'] 45 | else: 46 | self.openhabitemprefix = 'Rotex_' 47 | 48 | def rest_send(self, item, value): 49 | url = "http://%s:%s/rest/items/%s%s/state" % (self.openhabhost, str(self.openhabport), self.openhabitemprefix, item) 50 | try: 51 | r = requests.put(url, data=str(value)) 52 | except requests.exceptions.RequestException as e: 53 | rc = "ko" 54 | self.hpsu.printd("exception", "Error " + str(e.code) + ": " + str(e.reason)) 55 | 56 | def pushValues(self, vars=None): 57 | for r in vars: 58 | self.rest_send(r['name'], r['resp']) 59 | 60 | 61 | #if __name__ == '__main__': 62 | # app = openhab() 63 | 64 | # app.exec_() 65 | -------------------------------------------------------------------------------- /HPSU/plugins/pdf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | # requires reportlab, time, configparser, os, sys, pil 5 | 6 | # config inf conf_file (defaults): 7 | # [PDF] 8 | # FILE_PATH = "__the__users__homedir__" 9 | # FILE_NAME = "settings.pdf" 10 | 11 | from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, Table, TableStyle 12 | from reportlab.lib.styles import getSampleStyleSheet 13 | from reportlab.rl_config import defaultPageSize 14 | from reportlab.lib.pagesizes import A4 15 | from reportlab.lib import colors 16 | from reportlab.lib.units import cm,mm 17 | from operator import itemgetter 18 | from pathlib import Path 19 | import time 20 | import configparser 21 | import os 22 | import sys 23 | 24 | 25 | 26 | class export(): 27 | hpsu = None 28 | def __init__(self, hpsu=None, logger=None, config_file=None): 29 | self.page_height=defaultPageSize[1] 30 | self.page_width=defaultPageSize[0] 31 | self.styles = getSampleStyleSheet() 32 | self.title = "pyHPSU settings" 33 | self.pageinfo = "pyHPSU ver. 1.?" 34 | self.creation_time = time.asctime() 35 | self.logo = "/usr/share/pyHPSU/pyHPSU-logo.png" 36 | 37 | self.hpsu = hpsu 38 | self.logger = logger 39 | self.config_file = config_file 40 | self.config = configparser.ConfigParser() 41 | if os.path.isfile(self.config_file): 42 | self.config.read(self.config_file) 43 | else: 44 | sys.exit(9) 45 | 46 | # Path to save the pdf file 47 | if self.config.has_option('PDF', 'FILE_PATH'): 48 | self.file_path = self.config['FHEM']['FILE_PATH'] 49 | else: 50 | self.file_path = str(Path.home()) 51 | 52 | # Filename to save the pdf file 53 | if self.config.has_option('PDF', 'FILE_NAME'): 54 | self.file_name = self.config['FHEM']['FILE_NAME'] 55 | else: 56 | self.file_name = "settings.pdf" 57 | 58 | 59 | def myFirstPage(self,canvas, doc): 60 | canvas.saveState() 61 | canvas.drawImage("/usr/share/pyHPSU/pyHPSU-logo.jpg",cm,self.page_height-(2.5*cm),width=5*cm,height=5*cm,mask=None, preserveAspectRatio=True,anchor="sw") 62 | #canvas.rect(self.page_width-(1*cm),self.page_height-(5*cm),width=10*cm,height=5*cm) 63 | canvas.setFont('Helvetica-Bold',16) 64 | canvas.drawCentredString(self.page_width/2.0, self.page_height-50, self.title) 65 | #canvas.line(cm,self.page_height-50,self.page_width,self.page_height-50) 66 | canvas.setFont('Helvetica',9) 67 | canvas.drawString(cm, 0.75 * cm,"Page 1") 68 | canvas.drawCentredString(self.page_width/2.0, 0.75 * cm, self.pageinfo) 69 | canvas.drawRightString(self.page_width-cm,0.75 * cm, self.creation_time) 70 | canvas.restoreState() 71 | 72 | def myLaterPages(self,canvas, doc): 73 | canvas.saveState() 74 | canvas.setFont('Helvetica', 9) 75 | canvas.drawString(cm, 0.75 * cm,"Page %d" % (doc.page)) 76 | canvas.drawCentredString(self.page_width/2, 0.75 * cm, self.pageinfo) 77 | canvas.drawRightString(self.page_width-cm,0.75 * cm, self.creation_time) 78 | canvas.restoreState() 79 | 80 | 81 | 82 | 83 | 84 | def pushValues(self, vars=None): 85 | self.file=self.file_path + "/" + self.file_name 86 | doc = SimpleDocTemplate(self.file) 87 | Story = [Spacer(1,2*cm)] 88 | style = self.styles["Normal"] 89 | sorted_vars=sorted(vars, key=itemgetter('name')) 90 | data=[["Name","current value","writeable"]] 91 | for r in sorted_vars: 92 | name=r["name"] 93 | if self.hpsu.command_dict[name]["writable"]=="true": 94 | writable="yes" 95 | else: 96 | writable="no" 97 | 98 | d=[r["name"],r["resp"],writable] 99 | data.append(d) 100 | t=Table(data,colWidths=(50*mm,50*mm,20*mm)) 101 | 102 | t.setStyle(TableStyle([('ALIGN',(1,1),(-1,-1),'LEFT'), 103 | ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), 104 | ('BOX', (0,0), (-1,-1), 0.25, colors.black), 105 | ])) 106 | #if self.hpsu.command_dict[name]["writable"]=="true": 107 | #bogustext = ("%-20s - %-10s" % (r["name"], r["resp"])) 108 | #p = Paragraph(bogustext, style) 109 | #Story.append(p) 110 | #Story.append(Spacer(1,0.2*cm)) 111 | 112 | Story.append(t) 113 | doc.build(Story, onFirstPage=self.myFirstPage, onLaterPages=self.myLaterPages) 114 | 115 | 116 | 117 | 118 | 119 | if __name__ == '__main__': 120 | app = export() 121 | 122 | app.exec_() 123 | 124 | 125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | **Using pyHPSU may cause _damage_ to the heating system. The use of pyHPSU is at your own risk. The creator can not be held responsible for damage.** 3 | 4 | **You may risk a loss of warranty and support from the manufacturer!!!!** 5 | 6 | **This software is not supported by the manufacturer!!!!** 7 | 8 | # Welcome to pyHPSU 9 | pyHPSU is a set of python scripts and other files to read and modify the values of the Rotex® HPSU (possibly) also identical heating pumps from daikin®). 10 | 11 | It is based on the idea and the work of 12 | **[Vanni Brutto alias Zanac](https://github.com/zanac/pyHPSU)** 13 | 14 | It is expandable via plugins to send data to other systems and databases. 15 | At the momeent, Emoncms, fhem, homematic, influxdb, mqtt, mysql and openhab are supported. 16 | 17 | It works with [SocketCan](https://elinux.org/CAN_Bus) __OR__ the [elm327](https://en.wikipedia.org/wiki/ELM327) based serial-can interfaces. 18 | The advantage of SocketCan: it can handle multiple instances or programs talking over the same can interface or you can query multiple values with one command. Message queuing is done by the kernel. For serial can interfaces (like the Elm327) you need a server which handles the messages. To do this, pyHPSUd.py is there. It handles multiple pyHPSU.py session via rabbitMQ. 19 | 20 | 21 | # Hardware setup 22 | 1. Via Elm327 interface 23 | - Most cheap china replicas will not work because the "AT PP" command is not implemented. A purchase recommendation is as follows: https://www.totalcardiagnostics.com/elm327 or ahermann86 is using https://www.amazon.de/dp/B06XJ6GQZX/ref=cm_sw_em_r_mt_dp_U_OLP.CbG0Z7YKR 24 | - It is recommended to order a matching obd2 socket (16pol) to connect the can adapter 25 | - Connect the CAN-High cable pin 6, the CAN-Low cable pin 14 and CAN signal ground pin 5 to the hpsu mainboards "J13" connector. (Power on the CAN-Side is not needed) 26 | - look at your systems "dmesg" while connecting to get the device name 27 | 28 | 2. SocketCan 29 | - connect the Pins from the HPSU mainboards "J13" connector to the pins of your can interface. Needed are canH, canL and ground. 30 | - for debian (and other systems) and the following to /etc/network/interfaces: 31 | ``` 32 | auto can0 33 | iface can0 inet manual 34 | pre-up /sbin/ip link set $IFACE type can bitrate 20000 triple-sampling on 35 | up /sbin/ifconfig $IFACE up 36 | down /sbin/ifconfig $IFACE down 37 | ``` 38 | 39 | 40 | # Software setup 41 | 42 | pyHPSU only runs on unix/linux based systems. 43 | 1. To run pyHPSU you need python3 and these python packages: 44 | - python-can==3.3.4 45 | - serial 46 | - pika 47 | - requests 48 | - mysql.connector (used by the db plugin) 49 | - urllib3 (used by the homematic plugin) 50 | - paho-mqtt (used by the mqtt plugin) 51 | - influxdb (used by the influxdb plugn) 52 | 53 | 2. git clone https://github.com/Spanni26/pyHPSU 54 | 3. cd pyHPSU 55 | 4. chmod +x install.sh 56 | 5. sh install.sh 57 | 58 | # Using pyHPSU 59 | ## PyHPSU defaults 60 | - can-device: SocketCan (Driver canpi, for elm327 specify the driver with -d canelm327 and the line with e.g. -p /dev/ttyUSB ) 61 | - OutputFormat: JSON (other formats or output devices can be specified with "-o", the usage via "pyHPSU.py -?") 62 | 63 | To get a list of all available commands call: 64 | root@rotex:# pyHPSU.py -h 65 | 66 | To get a bit more information about a single command: 67 | root@rotex:# pyHPSU.py -h -c \ 68 | e.g. 69 | root@rotex:# pyHPSU.py -h -c t_hs 70 | 71 | To query a value (e.g. t_hs): 72 | root@rotex:# pyHPSU.py -c t_hs 73 | 74 | The default setting is the output to the console in json format, so the output will look like this: 75 | [{'name': 't_hs', 'resp': '32.00', 'timestamp': 1544534667.414178}] 76 | 77 | 78 | ## Output options ("-o \") 79 | ### CSV 80 | Output is send to console in CSV format (comma separated value) 81 | 82 | ### DB 83 | If a database should be used simply create a mysql DB with collation "utf8_bin", edit the pyhpsu.conf and select "DB" as output type 84 | Configure it in /etc/pyHPSU/pyhpsu.conf (look at the code of /usr/lib/python3/dist-packages/HPSU/plugins/db.py to find a template). 85 | 86 | ### EMONCMS 87 | Send the data to an emoncms instance (locally or the web version) 88 | Configure it in /etc/pyHPSU/pyhpsu.conf (look at the code of /usr/lib/python3/dist-packages/HPSU/plugins/emoncms.py to find a template). 89 | 90 | ### FHEM 91 | Send the data to a fhem instance. Atm only pushing the values via telnet to port 7072 is supported. 92 | Configure it in /etc/pyHPSU/pyhpsu.conf (look at the code of /usr/lib/python3/dist-packages/HPSU/plugins/fhem.py to find a template). 93 | 94 | ### HOMEMATIC 95 | Send the data to homematic. Therefore the xmlapi has to be installed on the ccu, a system variable has to be configured and the ise_id of this variable must be configured in the pyHPSU.conf (look ath the code of /usr/lib/python3/dist-packages/HPSU/plugins/fhem.py to find a template). 96 | 97 | ### INFLUXDB 98 | Send the data to the InfluxDB Time Series database. 99 | Configure it in /etc/pyHPSU/pyhpsu.conf (look at the code of /usr/lib/python3/dist-packages/HPSU/plugins/influxdb.py to find a template). 100 | 101 | ### MQTT 102 | Send the data to an MQTT broker. 103 | Configure it in /etc/pyHPSU/pyhpsu.conf (look at the code of /usr/lib/python3/dist-packages/HPSU/plugins/mqtt.py to find a template). 104 | 105 | ### OPENHAB 106 | Send the data to openHAB. Create an item for every command you want to use. You have to use a Prefix like `Rotex_` for all pyHPSU related item names. So pyHPSU will push every value to a item named [Prefix][command]. 107 | For example, if you want to send commands mode and t_dhw1 to openHAB, create those items in you [openHAB item config](https://www.openhab.org/docs/configuration/items.html). 108 | ``` 109 | Number Rotex_mode "Modus [MAP(heatpump_mode.map):%s]" 110 | Number Rotex_t_dhw1 "Temperatur im Warmwasserspeicher [%.1f °C]" 111 | ``` 112 | For commands like mode, which a number represents a state, you can use openHABs [mapping feature](https://www.openhab.org/addons/transformations/map/) to map state numbers to a textual description. 113 | 114 | Point pyHPSU to your openHAB system in /etc/pyHPSU/pyhpsu.conf file. Also use Auto Mode and configure your commands in `[JOBS]` section. 115 | ``` 116 | [OPENHAB] 117 | HOST = hostname_or_ip 118 | PORT = 8080 119 | ITEMPREFIX = Rotex_ 120 | 121 | [JOBS] 122 | mode = 30 123 | t_dhw1 = 60 124 | ``` 125 | 126 | ## Modes 127 | pyHPSU.py can be run un different modes. 128 | 1. Standalone 129 | You can run the pyHPSU.py in standalone mode forom the command line. 130 | e.g. query the value of t_hs, output in CSV format, using an elm327 interface on port /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_-if00-port0 131 | root@rotex:# pyHPSU.py -c t_hs -d elm327 -p /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_-if00-port0 -o CSV 132 | e.g. ask the heating pump for an pending error, output in JSON format, using an SocketCan interface 133 | root@rotex:# pyHPSU.py -c error -o JSON -d canpi 134 | or simply (cause JSON and canpi are the defaults): 135 | root@rotex:# pyHPSU.py -c error 136 | 137 | 2. Auto Mode 138 | The pyHPSU.py can be run in "auto mode". You can define values which should be querried in different periods. This is done at /etc/pyHPSU/pyhpsu.conf. 139 | At the "jobs" section add the value and the period (as shown by the examples) and addopt the section "PYHPSU" to your needs. Then, run the pyHPSU.py with the parameter "-a" 140 | e.g. 141 | root@rotex:# pyHPSU.py -a 142 | 143 | 3. With Message Broker (only needed with serial intrerfaces like Elm327) 144 | A serial line can only be used by one process at a time. So, if you query more then one value at a time or you run multiple instances of pyHPSU.py you can run in errors. 145 | In this mode, every query from pyHPSU.py is sent to the pyHPSUD.py. This daemon deals with the message broker "rabbitmq" which sends one query at a time and sorts the answers to the correct sending process. 146 | For that, install the message broker "rabbitmq". 147 | You also have to configure the config file /etc/pyHPSU/pyhpsu.conf at section "PYHPSUD". 148 | Here, specify the driver, language and serial port to use. 149 | The pyHPSUD.py is started via systemd: 150 | root@rotex:# systemctl enable hpsud.service 151 | root@rotex:# systemctl start hpsud.service 152 | 153 | 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) 154 | i.e. root@rotex:# pyHPSU.py -d HPSUD -c t_dhw_setpoint1 155 | 156 | -------------------------------------------------------------------------------- /comandi_rotex_hpsu_elm327.xlsm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Spanni26/pyHPSU/14e784b222da5957df2cd5a9282d1534ffaf7ab7/comandi_rotex_hpsu_elm327.xlsm -------------------------------------------------------------------------------- /contrib/README.md: -------------------------------------------------------------------------------- 1 | # Scripts 2 | 3 | ## Capture-Publish 4 | 5 | Set of useful scripts to automatically read from HPSU Compact and publish them on the cloud ([emoncms.org](http://emoncms.org)) a configurable list of variables. 6 | Copy the *.service and the *.timer to /etc/systemd/system and enable and 7 | start it via systemctl (e.g. "systemctl enable hpsu.fast.timer" and and 8 | "systemctl start hpsu.fast.timer") 9 | 10 | ## Control 11 | 12 | Scripts to automatically control HPSU: 13 | * Chrono-thermostat (heating and cooling) 14 | * Flow Temperature Control (heating only) 15 | * DHW / Cooling Setpoint Scheduling 16 | -------------------------------------------------------------------------------- /contrib/capture-publish/hpsu.fast.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=HPSU FAST Daemon 3 | 4 | [Service] 5 | Type=simple 6 | ExecStart=/usr/share/pyHPSU/scripts/capture-publish/hpsu.fast.sh 7 | PIDFile=/tmp/hpsu.fast.pid 8 | MaxRuntimeSec=8 9 | -------------------------------------------------------------------------------- /contrib/capture-publish/hpsu.fast.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | python3 /usr/share/pyHPSU/bin/pyHPSU.py -d PYCAN -c flow_rate -c mode -c bpv -c posmix -c t_v1 -c t_dhw1 -c t_vbh -c t_r1 -c tliq2 -c ehs -c pump -o CLOUD -u EMONCMS -g /var/log/hpsu.fast.log -v 1 3 | -------------------------------------------------------------------------------- /contrib/capture-publish/hpsu.fast.timer: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Runs HPSU Fast Script 3 | 4 | [Timer] 5 | OnBootSec=30 6 | OnUnitActiveSec=11 7 | Unit=hpsu.fast.service 8 | AccuracySec=1 9 | Persistent=true 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /contrib/capture-publish/hpsu.listener.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=HPSU LISTENER Daemon 3 | 4 | [Service] 5 | Type=simple 6 | ExecStart=/home/pi/hpsu.listener.sh 7 | PIDFile=/tmp/hpsu.listener.pid 8 | -------------------------------------------------------------------------------- /contrib/capture-publish/hpsu.listener.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | python /home/pi/pyHPSU-master/pyListener.py 3 | -------------------------------------------------------------------------------- /contrib/capture-publish/hpsu.medium.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=HPSU MEDIUM Daemon 3 | 4 | [Service] 5 | Type=simple 6 | ExecStart=/usr/share/pyHPSU/scripts/capture-publish/hpsu.medium.sh 7 | PIDFile=/tmp/hpsu.medium.pid 8 | MaxRuntimeSec=8 9 | -------------------------------------------------------------------------------- /contrib/capture-publish/hpsu.medium.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | python3 /usr/share/pyHPSU/bin/pyHPSU.py -d PYCAN -c t_hc_set -c t_dhw_set -c t_ext -c t_outdoor_ot1 -c ta2 -o CLOUD -u EMONCMS -g /var/log/hpsu.medium.log -v 1 3 | -------------------------------------------------------------------------------- /contrib/capture-publish/hpsu.medium.timer: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Runs HPSU Medium Script 3 | 4 | [Timer] 5 | OnBootSec=25 6 | OnUnitActiveSec=61 7 | Unit=hpsu.medium.service 8 | AccuracySec=1 9 | Persistent=true 10 | 11 | [Install] 12 | WantedBy=timers.target 13 | -------------------------------------------------------------------------------- /contrib/capture-publish/hpsu.slow.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=HPSU SLOW Daemon 3 | 4 | [Service] 5 | Type=simple 6 | ExecStart=/usr/share/pyHPSU/scripts/capture-publish/hpsu.slow.sh 7 | PIDFile=/tmp/hpsu.slow.pid 8 | MaxRuntimeSec=8 9 | -------------------------------------------------------------------------------- /contrib/capture-publish/hpsu.slow.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | python3 /usr/share/pyHPSU/bin/pyHPSU.py -d PYCAN -c qboh -c qchhp -c qch -c qwp -c qdhw -c t_dhw_setpoint1 -c hyst_hp -c t_dhw_set -o CLOUD -u EMONCMS -g /var/log/hpsu.slow.log -v 1 3 | -------------------------------------------------------------------------------- /contrib/capture-publish/hpsu.slow.timer: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Runs HPSU Fast Script 3 | 4 | [Timer] 5 | OnBootSec=20 6 | OnUnitActiveSec=293 7 | Unit=hpsu.slow.service 8 | AccuracySec=1 9 | Persistent=true 10 | 11 | [Install] 12 | WantedBy=timers.target 13 | -------------------------------------------------------------------------------- /contrib/capture-publish/pyListener.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys, time 5 | import requests 6 | import json 7 | import math 8 | import binascii 9 | #import statistics 10 | import struct 11 | 12 | import logging 13 | import logging.handlers 14 | 15 | from collections import deque 16 | import itertools 17 | from scipy.signal import butter, filtfilt 18 | import numpy as np 19 | 20 | logHandler = logging.handlers.TimedRotatingFileHandler("/home/pi/listener.log",when="midnight") 21 | logFormatter = logging.Formatter('%(asctime)s %(message)s') 22 | logHandler.setFormatter( logFormatter ) 23 | logger = logging.getLogger() 24 | logger.addHandler( logHandler ) 25 | logger.setLevel( logging.ERROR ) 26 | 27 | logging.getLogger("requests").setLevel(logging.WARNING) 28 | logging.getLogger("urllib3").setLevel(logging.WARNING) 29 | 30 | try: 31 | import can 32 | except Exception: 33 | pass 34 | 35 | # Variable Name => String (Costante) 36 | # CAN Signature => Hex (Costante) 37 | # [Timestamp, Value] Vector => Float 38 | # Last Publish Timestamp => Time 39 | # Average Value => Float (corrisponde alla media aritmetica di Value [x]) 40 | 41 | dati = [ 42 | [bytearray([0x32, 0x10, 0xFA, 0xC0, 0xF6]), deque([], 400), deque([], 400), "_mode", False], 43 | [bytearray([0x32, 0x10, 0xFA, 0xC0, 0xFB]), deque([], 400), deque([], 400), "_bpv", False], 44 | [bytearray([0x32, 0x10, 0xFA, 0x06, 0x9B]), deque([], 400), deque([], 400), "_posmix", False], 45 | [bytearray([0x32, 0x10, 0xFA, 0xC0, 0xF7]), deque([], 400), deque([], 400), "_pump", False], 46 | [bytearray([0x32, 0x10, 0xFA, 0xC0, 0xFC]), deque([], 400), deque([], 400), "_t_v1", True], 47 | [bytearray([0x32, 0x10, 0xFA, 0xC0, 0xFD]), deque([], 400), deque([], 400), "_t_dhw1", True], 48 | [bytearray([0x32, 0x10, 0xFA, 0xC0, 0xFE]), deque([], 400), deque([], 400), "_t_vbh", True], 49 | [bytearray([0x32, 0x10, 0xFA, 0xC1, 0x00]), deque([], 400), deque([], 400), "_t_r1", True], 50 | [bytearray([0x32, 0x10, 0xFA, 0xC0, 0xF9]), deque([], 400), deque([], 400), "_ehs", False], 51 | [bytearray([0x62, 0x10, 0x04]), deque([], 400), deque([], 400), "_t_hc_set", False], 52 | [bytearray([0x32, 0x10, 0x03]), deque([], 400), deque([], 400), "_t_dhw_set", False], 53 | [bytearray([0x62, 0x10, 0xFA, 0x0A, 0x0C]), deque([], 400), deque([], 400), "_t_ext", False], 54 | [bytearray([0x32, 0x10, 0xFA, 0xC0, 0xFF]), deque([], 400), deque([], 400), "_t_outdoor_ot1", False], 55 | [bytearray([0x32, 0x10, 0xFA, 0xC1, 0x05]), deque([], 400), deque([], 400), "_ta2", False], 56 | [bytearray([0x32, 0x10, 0x13]), deque([], 400), deque([], 400), "_t_dhw_setpoint1", False], 57 | [bytearray([0x32, 0x10, 0xFA, 0x06, 0x91]), deque([], 400), deque([], 400), "_hyst_hp", False], 58 | [bytearray([0xd2, 0x10, 0xFA, 0x01, 0x12]), deque([], 400), deque([], 400), "_mode_01", False], 59 | [bytearray([0x32, 0x10, 0xFA, 0x01, 0xDA]), deque([], 400), deque([], 400), "_flow_rate", True], 60 | [bytearray([0x32, 0x10, 0xFA, 0xC1, 0x03]), deque([], 400), deque([], 400), "_tliq2", False], 61 | [bytearray([0x32, 0x10, 0xFA, 0x09, 0x1C]), deque([], 400), deque([], 400), "_qboh", False], 62 | [bytearray([0x32, 0x10, 0xFA, 0x09, 0x20]), deque([], 400), deque([], 400), "_qchhp", False], 63 | [bytearray([0x32, 0x10, 0xFA, 0x06, 0xA7]), deque([], 400), deque([], 400), "_qch", False], 64 | [bytearray([0x32, 0x10, 0xFA, 0x09, 0x30]), deque([], 400), deque([], 400), "_qwp", False], 65 | [bytearray([0x32, 0x10, 0xFA, 0x09, 0x2C]), deque([], 400), deque([], 400), "_qdhw", False], 66 | [bytearray([0x22, 0x10, 0xFA, 0xC0, 0xB4]), deque([], 400), deque([], 400), "_water_pressure", False] 67 | ] 68 | 69 | b, a = butter(5, 1, btype='low', analog=False) 70 | 71 | class CanListener(can.Listener): 72 | def on_message_received(self, msg): 73 | logger.debug("MSG Received") 74 | found = False 75 | for i in range(len(dati)): 76 | lungh = len(dati[i][0]) 77 | #logger.debug("%d %s %s", lungh, binascii.hexlify(msg.data[2:lungh]), binascii.hexlify(dati[i][0][2:lungh])) 78 | if (msg.data[2:lungh] == dati[i][0][2:lungh]): 79 | found = True 80 | 81 | if (msg.data[0:1] == dati[i][0][0:1]): 82 | # dati nativi dai sensori 83 | 84 | nuovo_dato = struct.unpack(">h", msg.data[lungh:lungh+2])[0] 85 | 86 | # filtri ad-hoc 87 | 88 | # rimuove i buchi di misura sul flow_rate in base al valore di mode 89 | 90 | if ((nuovo_dato == 0) and (i == 17) and (len(dati[0][1]) > 0) and 91 | (dati[0][1][-1] != 0) and (len(dati[i][1]) > 0)): 92 | dati[i][1].append(dati[i][1][-1]) 93 | else: 94 | dati[i][1].append(nuovo_dato) 95 | 96 | if ((dati[i][4] == True) and (len(dati[i][1]) > 18)): 97 | 98 | ultimi_10 = list(itertools.islice(dati[i][1], len(dati[i][1]) - 11, len(dati[i][1]) - 1)) 99 | logger.debug("%4d %19s => %10s %200s", msg.arbitration_id, binascii.hexlify(msg.data).ljust(19), dati[i][3].ljust(15), ultimi_10) 100 | dati[i][2].append(np.mean(ultimi_10)) 101 | y = filtfilt(b, a, dati[i][1]) 102 | logger.info("%4d %19s => %10s %200s %d", msg.arbitration_id, binascii.hexlify(msg.data).ljust(19), dati[i][3].ljust(15), y, len(y)) 103 | else: 104 | dati[i][2].append(dati[i][1][-1]) 105 | 106 | logger.debug(binascii.hexlify(msg.data)) 107 | 108 | logger.info("%4d %19s => %10s %10s", msg.arbitration_id, binascii.hexlify(msg.data).ljust(19), dati[i][3].ljust(15), dati[i][1]) 109 | logger.info("%4d %19s => %10s %10s %d", msg.arbitration_id, binascii.hexlify(msg.data).ljust(19), dati[i][3].ljust(15), dati[i][2], nuovo_dato) 110 | 111 | OEM_API_KEY = '3f31332ec065af95bdcfec650899febd' 112 | 113 | valore = {} 114 | logger.debug(nuovo_dato) 115 | logger.debug(dati[i][1][-1]) 116 | logger.debug(dati[i][2][-1]) 117 | valore[dati[i][3]] = round(float(dati[i][2][-1]), 2) 118 | valore_json = json.dumps(valore) 119 | 120 | OEM_APIURL = "https://emoncms.org/api/post?apikey=%s&time:%s&json=%s&node=999" % (OEM_API_KEY, msg.timestamp, valore_json) 121 | 122 | logger.info("%4d %19s => %10s POSTING TO EMONCMS %s", msg.arbitration_id, binascii.hexlify(msg.data).ljust(19), dati[i][3].ljust(15), valore_json) 123 | 124 | try: 125 | r = requests.get(OEM_APIURL, timeout=5) 126 | except: 127 | logger.error(requests.exceptions.RequestException) 128 | 129 | else: 130 | logger.debug("%4d %19s => %10s READ REQUEST %s %s", msg.arbitration_id, binascii.hexlify(msg.data).ljust(19), dati[i][3].ljust(15), binascii.hexlify(msg.data[0:2]), binascii.hexlify(dati[i][0][0:2])) 131 | break 132 | if (found == False): 133 | logger.debug("%4d %19s => UNKNOWN", msg.arbitration_id, binascii.hexlify(msg.data).ljust(19)) 134 | 135 | 136 | try: 137 | #can_filters = [{"can_id": "0x1c1"}] 138 | bus = can.interface.Bus(channel='can0', bustype='socketcan') 139 | except Exception: 140 | logger.error ("exception open bus") 141 | sys.exit(0) 142 | 143 | a_listener = CanListener() 144 | notifier = can.Notifier(bus, [a_listener]) 145 | 146 | logger.info("Can Logger Started") 147 | 148 | #logger.debug(dati[0]) 149 | 150 | #for i in range(len(dati)): 151 | # time.sleep(1) 152 | # logger.debug(i) 153 | # msg = can.Message(arbitration_id=0x190, data=dati[i][0], extended_id=False, dlc=7) 154 | # logger.debug(msg) 155 | # bus.send(msg) 156 | 157 | try: 158 | while True: 159 | time.sleep(1) 160 | #power = 1.163 * float(dati[17][2][0]) * 0.1 * ( float(dati[6][2][0]) - float(dati[7][2][0]) + 0.379 + 0.111) 161 | # print(power) 162 | #logger.debug("Alive !") 163 | except KeyboardInterrupt: 164 | bus.shutdown() 165 | -------------------------------------------------------------------------------- /contrib/control/Chrono-Thermostat/README.md: -------------------------------------------------------------------------------- 1 | # Chrono-thermostat 2 | 3 | Set of useful scripts to automatically control: 4 | * heating timeframe 5 | * cooling timeframe 6 | * heating setpoints 7 | * cooling setpoints 8 | -------------------------------------------------------------------------------- /contrib/control/Chrono-Thermostat/pyTermostato.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import requests 5 | import json 6 | import sys, time 7 | import datetime 8 | try: 9 | import can 10 | except Exception: 11 | pass 12 | 13 | import logging 14 | import logging.handlers 15 | 16 | logHandler = logging.handlers.TimedRotatingFileHandler("/home/pi/termostato.log",when="midnight") 17 | logFormatter = logging.Formatter('%(asctime)s %(message)s') 18 | logHandler.setFormatter( logFormatter ) 19 | logger = logging.getLogger() 20 | logger.addHandler( logHandler ) 21 | logger.setLevel( logging.DEBUG ) 22 | 23 | logging.getLogger("requests").setLevel(logging.WARNING) 24 | logging.getLogger("urllib3").setLevel(logging.WARNING) 25 | logging.getLogger("can").setLevel(logging.WARNING) 26 | 27 | com_leggi_modooperativo = "31 00 FA 01 12 00 00 00" 28 | must_switch_off = False 29 | must_switch_on = False 30 | must_switch_cool_off = False 31 | must_switch_cool_on = False 32 | time_is_on = True 33 | time_cool_is_on = True 34 | id = "680" 35 | receiver_id = int(id, 16) 36 | temp_heat_setpoint = 21.5 37 | temp_cool_setpoint = 25.3 38 | temp_hyst = 0.4 39 | 40 | if __name__ == "__main__": 41 | 42 | errore_lettura = False 43 | 44 | # APERTURA CONNESSIONE CAN BUS 45 | 46 | try: 47 | bus = can.interface.Bus(channel='can0', bustype='socketcan_native') 48 | except Exception: 49 | print ("exception open bus") 50 | sys.exit(0) 51 | 52 | # legge modo operativo corrente da HPSU 53 | 54 | if (errore_lettura != True): 55 | command = com_leggi_modooperativo 56 | msg_data = [int(r, 16) for r in command.split(" ")] 57 | 58 | try: 59 | msg = can.Message(arbitration_id=receiver_id, data=msg_data, extended_id=False, dlc=7) 60 | bus.send(msg) 61 | except Exception: 62 | print('exception', 'Error sending msg') 63 | sys.exit(0) 64 | try: 65 | rcbus = bus.recv(1.0) 66 | except Exception: 67 | logger.error('exception', 'Error reading msg') 68 | sys.exit(0) 69 | 70 | modo_operativo = -10.0 71 | 72 | 73 | if rcbus and rcbus.data and (len(rcbus.data) >= 7) and (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]): 74 | modo_operativo = rcbus.data[5] 75 | 76 | # skippa dati sballati 77 | 78 | if (modo_operativo == -10.0): 79 | errore_lettura = True 80 | logger.error ("HPSU : *** ERRORE LETTURA PARAMETRO MODO OPERATIVO CORRENTE ***") 81 | sys.exit(1) 82 | 83 | if (modo_operativo == 3.0): 84 | etichetta = "HEATING" 85 | elif (modo_operativo == 5.0): 86 | etichetta = "SUMMER" 87 | elif (modo_operativo == 17.0): 88 | etichetta = "COOLING" 89 | else: 90 | etichetta = "NOT PLANNED" 91 | logger.info("HPSU : Current mode is %s", etichetta) 92 | # verifica di essere nell'orario di funzionamento previsto 93 | 94 | now = datetime.datetime.now() 95 | now = now.replace(microsecond=0) 96 | time_heat_start = now.replace(hour=11, minute=0, second=0, microsecond=0) 97 | time_heat_end = now.replace(hour=21, minute=0, second=0, microsecond=0) 98 | 99 | time_cool_start = now.replace(hour=20, minute=0, second=0, microsecond=0) 100 | now += datetime.timedelta(days=1) 101 | time_cool_end = now.replace(hour=7, minute=59, second=0, microsecond=0) 102 | now += datetime.timedelta(days=-1) 103 | 104 | logger.info("SMART-THERMOSTAT : HEATING => %s < t < %s" % (time_heat_start.strftime("%d/%m %H:%M"), time_heat_end.strftime("%d/%m %H:%M"))) 105 | logger.info("SMART-THERMOSTAT : COOLING => %s < t < %s" % (time_cool_start.strftime("%d/%m %H:%M"), time_cool_end.strftime("%d/%m %H:%M"))) 106 | 107 | if ((now < time_heat_start) or (now > time_heat_end)): 108 | time_is_on = False 109 | # verifico se devo spegnere 110 | if (errore_lettura != True) and (modo_operativo == 3.0): 111 | #devo commutare da riscaldamento ad estate 112 | must_switch_off = True 113 | #sys.exit(0) 114 | 115 | if ((now < time_cool_start) or (now > time_cool_end)): 116 | time_cool_is_on = False 117 | # verifico se devo spegnere 118 | if (errore_lettura != True) and (modo_operativo == 17.0): 119 | #devo commutare da raffrescamento ad estate 120 | must_switch_cool_off = True 121 | #sys.exit(0) 122 | 123 | # RECUPERA LA TEMPERATURA INTERNA DA OEM 124 | 125 | OEM_API_KEY = 'f7f5d003c595ed3285cd616521aa5aab' 126 | OEM_APIURL = 'http://emoncms.org/feed/value.json?id=36238&apikey=' + OEM_API_KEY 127 | 128 | try: 129 | r = requests.get(OEM_APIURL, timeout=5) 130 | except: 131 | logger.error(requests.exceptions.RequestException) 132 | sys.exit(1) 133 | 134 | if r.status_code != 200: 135 | logger.error ("Error:", r.status_code) 136 | sys.exit(1) 137 | 138 | json_temperature = r.json() 139 | 140 | temperatura_interna = float(json_temperature) 141 | 142 | OEM_APIURL = 'http://emoncms.org/feed/value.json?id=36240&apikey=' + OEM_API_KEY 143 | 144 | try: 145 | r = requests.get(OEM_APIURL, timeout=5) 146 | except: 147 | logger.error(requests.exceptions.RequestException) 148 | sys.exit(1) 149 | 150 | if r.status_code != 200: 151 | logger.error ("Error:", r.status_code) 152 | sys.exit(1) 153 | 154 | json_umidita = r.json() 155 | 156 | umidita_interna = float(json_umidita) 157 | 158 | 159 | if ( 160 | ((modo_operativo == 3.0) and (temperatura_interna > temp_heat_setpoint + temp_hyst)) 161 | or 162 | must_switch_off 163 | ) : 164 | # spegni mettendo in modalita' Estate 165 | command = "32 00 FA 01 12 05 00" 166 | must_switch_off = True 167 | 168 | if ( 169 | ((modo_operativo != 3.0) and (temperatura_interna < temp_heat_setpoint - temp_hyst)) 170 | or 171 | must_switch_on 172 | ) : 173 | # accendi riscaldamento mettendo in modalita' Riscaldamento 174 | command = "32 00 FA 01 12 03 00" 175 | if (modo_operativo != 3.0): 176 | must_switch_on = True 177 | 178 | if ( 179 | ((modo_operativo == 17.0) and (temperatura_interna < temp_cool_setpoint - temp_hyst)) 180 | or 181 | must_switch_cool_off 182 | ) : 183 | # spegni mettendo in modalita' Estate 184 | command = "32 00 FA 01 12 05 00" 185 | must_switch_cool_off = True 186 | 187 | if ( 188 | ((modo_operativo != 17.0) and (temperatura_interna > temp_cool_setpoint + temp_hyst)) 189 | or 190 | must_switch_cool_on 191 | ) : 192 | # accendi raffrescamento mettendo in modalita' Raffrescamento 193 | command = "32 00 FA 01 12 11 00" 194 | if (modo_operativo != 3.0): 195 | must_switch_cool_on = True 196 | 197 | # 01 - Standby 198 | # 11 - Raffreddare 199 | # 04 - Ridurre 200 | # 03 - Riscaldare 201 | # 05 - Estate 202 | # 0b - Automatico 1 203 | # 0c - Automatico 2 204 | 205 | logger.info("SMART-THERMOSTAT : HEATING => %02.1f °C < T Int. < %02.1f °C" % (temp_heat_setpoint - temp_hyst, temp_heat_setpoint + temp_hyst)) 206 | logger.info("SMART-THERMOSTAT : COOLING => %02.1f °C < T Int. < %02.1f °C" % (temp_cool_setpoint - temp_hyst, temp_cool_setpoint + temp_hyst)) 207 | 208 | logger.info("OEM : T Int. = %02.1f °C" % temperatura_interna) 209 | logger.info("OEM : HR Int. = %02.1f %%" % umidita_interna) 210 | 211 | if (must_switch_on): 212 | logger.info("HPSU : Changing mode to HEATING") 213 | if (must_switch_off): 214 | logger.info("HPSU : Changing mode to SUMMER") 215 | 216 | if (must_switch_cool_on): 217 | logger.info("HPSU : Changing mode to COOLING") 218 | if (must_switch_cool_off): 219 | logger.info("HPSU : Changing mode to SUMMER") 220 | 221 | if (must_switch_on or must_switch_off or must_switch_cool_on or must_switch_cool_off) : 222 | msg_data = [int(r, 16) for r in command.split(" ")] 223 | try: 224 | msg = can.Message(arbitration_id=receiver_id, data=msg_data, extended_id=False, dlc=7) 225 | #logger.info("HPSU : Changing heat pump mode from %s to %s" % (etichetta, msg)) 226 | bus.send(msg) 227 | except Exception: 228 | logger.error('exception', 'Error sending msg') 229 | sys.exit(1) 230 | -------------------------------------------------------------------------------- /contrib/control/Chrono-Thermostat/termostato.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Termostato Daemon 3 | 4 | [Service] 5 | Type=simple 6 | ExecStart=/home/pi/termostato.sh 7 | PIDFile=/tmp/termostato.pid 8 | MaxRuntimeSec=8 9 | Restart=always 10 | RestartSec=30 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | Alias=termostato.service 15 | -------------------------------------------------------------------------------- /contrib/control/Chrono-Thermostat/termostato.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | python3 /home/pi/pyHPSU-master/pyTermostato.py 209 221 3 | -------------------------------------------------------------------------------- /contrib/control/Chrono-Thermostat/termostato.timer: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Runs Termostato Script 3 | 4 | [Timer] 5 | OnBootSec=20 6 | OnUnitActiveSec=337 7 | Unit=termostato.service 8 | AccuracySec=1 9 | Persistent=true 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /contrib/control/Flow-Control/README.md: -------------------------------------------------------------------------------- 1 | # Flow Temperature Control 2 | 3 | Scripts to control heating flow temperature: 4 | * PI Controller (inside temperature vs setpoint) 5 | * heating power control within HPSU specifications 6 | -------------------------------------------------------------------------------- /contrib/control/Flow-Control/mandata.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Smart Flow Temperature Controller 3 | 4 | [Service] 5 | Type=simple 6 | ExecStart=/home/pi/mandata.sh 7 | PIDFile=/tmp/mandata.pid 8 | Restart=always 9 | RestartSec=30 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | Alias=mandata.service 14 | 15 | -------------------------------------------------------------------------------- /contrib/control/Flow-Control/mandata.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | python3 /home/pi/pyHPSU-master/pyMandata.py 3 | -------------------------------------------------------------------------------- /contrib/control/Flow-Control/pyMandata.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys, time 5 | import requests 6 | import json 7 | import math 8 | 9 | import logging 10 | import logging.handlers 11 | 12 | logHandler = logging.handlers.TimedRotatingFileHandler("/home/pi/mandata.log",when="midnight") 13 | logFormatter = logging.Formatter('%(asctime)s %(message)s') 14 | logHandler.setFormatter( logFormatter ) 15 | logger = logging.getLogger() 16 | logger.addHandler( logHandler ) 17 | logger.setLevel( logging.INFO ) 18 | 19 | logging.getLogger("requests").setLevel(logging.WARNING) 20 | logging.getLogger("urllib3").setLevel(logging.WARNING) 21 | 22 | 23 | try: 24 | import can 25 | except Exception: 26 | pass 27 | 28 | from HPSU import HPSU 29 | 30 | logging.getLogger("can").setLevel(logging.WARNING) 31 | 32 | #da fare una sola volta in modo da ottenere un’istanza di hpsu 33 | 34 | hpsu = HPSU.HPSU(driver="PYCAN", port=None, cmd=[]) 35 | if (hpsu is None): 36 | logger.error("ERRORE CREAZIONE OGGETTO HPSU") 37 | 38 | # calcola il valore medio sugli ultimi 5 campioni 39 | 40 | def get_smooth(x): 41 | if not hasattr(get_smooth, "t"): 42 | get_smooth.t = [x,x,x,x,x] 43 | get_smooth.t[4] = get_smooth.t[3] 44 | get_smooth.t[3] = get_smooth.t[2] 45 | get_smooth.t[2] = get_smooth.t[1] 46 | get_smooth.t[1] = get_smooth.t[0] 47 | get_smooth.t[0] = x 48 | xs = (get_smooth.t[0]+get_smooth.t[1]+get_smooth.t[2]+get_smooth.t[3]+get_smooth.t[4])/5 49 | return(xs) 50 | 51 | def get_smooth_flow(x): 52 | if not hasattr(get_smooth_flow, "t"): 53 | get_smooth_flow.t = [x,x,x,x,x] 54 | get_smooth_flow.t[4] = get_smooth_flow.t[3] 55 | get_smooth_flow.t[3] = get_smooth_flow.t[2] 56 | get_smooth_flow.t[2] = get_smooth_flow.t[1] 57 | get_smooth_flow.t[1] = get_smooth_flow.t[0] 58 | get_smooth_flow.t[0] = x 59 | xs = (get_smooth_flow.t[0]+get_smooth_flow.t[1]+get_smooth_flow.t[2]+get_smooth_flow.t[3]+get_smooth_flow.t[4])/5 60 | return(xs) 61 | 62 | 63 | # COSTANTI 64 | 65 | # dati Daikin HPSU Compact 66 | # temperatura esterna, potenza al 100%, COP al 50% 67 | potenza_nominale=[[12,9.20,7.65],[11,9.06,7.33],[10,8.91,7.01],[9,8.77,6,69],[8,8.62,6.37],[7,8.48,6.05],[6,8.10,5.74],[5,7.72,5.43],[4,7.34,5.13],[3,6.96,4.82],[2,6.58,4.51],[1,6.47,4.33],[0,6.37,4.14],[-1,6.26,3.96],[-2,6.15,3.77],[-3,6.02,3.70],[-4,5.88,3.63],[-5,5.75,3.56],[-6,5.61,3.49],[-7,5.48,3.42]] 68 | 69 | temperatura_interna_nominale = 21.5 70 | ore_funzionamento = 13.0 71 | Kp = 0.5 72 | Dt = 60000.0 73 | Ki = 1 / 108000000.0 * Kp 74 | 75 | portata = 800.0 76 | 77 | id = "680" 78 | receiver_id = int(id, 16) 79 | 80 | com_scrivi_mandata = "32 00 FA 00 05 %s 00" 81 | com_leggi_testerna = "31 00 FA C0 FF 00 00 00" 82 | com_leggi_tritorno = "31 00 FA C1 00 00 00 00" 83 | com_leggi_modooperativo = "31 00 FA 01 12 00 00 00" 84 | com_leggi_mode = "31 00 FA C0 F6 00 00 00" 85 | com_leggi_tmandata = "C1 00 0F 00 00 00 00 00" 86 | 87 | # RECUPERA LA TEMPERATURA MEDIA PREVISTA PER LE PROSSIME 24 ORE DA WU 88 | 89 | WU_API_KEY = '14cd099d84ae0366' 90 | WU_COUNTRY = 'Italy' 91 | WU_LOCATION = 'Vigevano' 92 | WU_APIURL = 'http://api.wunderground.com/api/' + WU_API_KEY + '/hourly/q/' + WU_COUNTRY + '/' + WU_LOCATION + '.json' 93 | 94 | try: 95 | r = requests.get(WU_APIURL, timeout=5) 96 | except: 97 | logger.error(requests.exceptions.RequestException) 98 | 99 | if r.status_code != 200: 100 | logger.error ("Error:", r.status_code) 101 | 102 | json_weather = r.json() 103 | conta = 0 104 | temperatura_esterna_24ore = 0.0 105 | temperatura_esterna = [] 106 | ind_ora_max = 0 107 | temperatura_max = 0.0 108 | temperatura_min = 0.0 109 | temperatura_WU = 0.0 110 | 111 | for previsione_oraria in json_weather['hourly_forecast']: 112 | if (conta < 36): 113 | temperatura_WU = float(previsione_oraria['temp']['metric'].replace(u'\N{MINUS SIGN}', '-')) 114 | if (conta < 24) : 115 | temperatura_esterna_24ore += temperatura_WU 116 | if (temperatura_WU > temperatura_max): 117 | temperatura_max = temperatura_WU 118 | ind_ora_max = conta + 1 119 | if (temperatura_WU < temperatura_min): 120 | temperatura_min = temperatura_WU 121 | temperatura_esterna.append([int(previsione_oraria['FCTTIME']['hour']), float(previsione_oraria['temp']['metric'].replace(u'\N{MINUS SIGN}', '-'))]) 122 | conta += 1 123 | 124 | temperatura_esterna_24ore /= 24.0 125 | 126 | #print (temperatura_esterna) 127 | 128 | logger.info (ind_ora_max, temperatura_esterna[ind_ora_max]) 129 | 130 | #calcolo il fabbisogno di energia termica per le prossime 24 ore 131 | 132 | energia_termica = 66.11 * 114.35 * (temperatura_interna_nominale - temperatura_esterna_24ore) / 2544.0 133 | 134 | #determino la potenza termica in base al fabbisogno termico suddiviso su 22.0 ore di funzionamento; non deve scendere sotto il 30% come regime di funzionamento 135 | 136 | potenza_termica = max(energia_termica / 22.0, 0.35 * potenza_nominale[max(12 - round(temperatura_esterna_24ore), 0)][1]) 137 | 138 | ore_funzionamento = min(round (energia_termica / potenza_termica), 24.0) 139 | 140 | logger.info ("METEO+INVOLUCRO : T Esterna = %02.1f C => E Termica = %02.1f kWh => P t media = %01.2f kW su %02.0f ore" % (temperatura_esterna_24ore, energia_termica, potenza_termica, ore_funzionamento)) 141 | 142 | ind_ora_start = ind_ora_max 143 | ind_ora_end = ind_ora_max 144 | 145 | while (ind_ora_end - ind_ora_start < ore_funzionamento) : 146 | if (ind_ora_start >= 2) and (ind_ora_end < 35): 147 | if (potenza_nominale[max(12-round(temperatura_esterna[ind_ora_start-1][1]),0)][2] > potenza_nominale[max(12-round(temperatura_esterna[ind_ora_end+1][1]),0)][2]) : 148 | #if (temperatura_esterna[ind_ora_start - 1][1] > temperatura_esterna[ind_ora_end + 1][1]) : 149 | ind_ora_start -= 1 150 | else : 151 | ind_ora_end += 1 152 | else : 153 | if (ind_ora_end < 35) : 154 | ind_ora_end += 1 155 | else : 156 | ind_ora_start -= 1 157 | #logging.info ("METEO : ", ind_ora_start, temperatura_esterna[ind_ora_start], potenza_nominale[max(12-round(temperatura_esterna[ind_ora_start][1]),0)][2], ind_ora_end, temperatura_esterna[ind_ora_end], potenza_nominale[max(12-round(temperatura_esterna[ind_ora_end][1]),0)][2]) 158 | 159 | ora_start = temperatura_esterna[ind_ora_start][0] 160 | 161 | ora_end = temperatura_esterna[ind_ora_end][0] 162 | 163 | #print (ora_start, ora_end, ore_funzionamento) 164 | 165 | indice = ind_ora_start 166 | energia_termica_actual=0.0 167 | potenza_termica_corrente=0.0 168 | 169 | while (indice < ind_ora_end) : 170 | potenza_termica_corrente = min(max(0.3 * potenza_nominale[max(12 - round(temperatura_esterna[indice][1]), 0)][1], potenza_termica), 0.7 * potenza_nominale[max(12 - round(temperatura_esterna[indice][1]), 0)][1]) 171 | energia_termica_actual += potenza_termica_corrente 172 | logger.info("METEO+HPSU : #%2d => %2s:00 => %2.0f C => P t nom. %1.2f kW (30%%) %1.2f kW (70%%) => Pt = %1.2f kW ; COP 50%% = %01.2f" % 173 | ( 174 | indice - ind_ora_start + 1, 175 | temperatura_esterna[indice][0], 176 | temperatura_esterna[indice][1], 177 | 0.3 * potenza_nominale[max(12 - round(temperatura_esterna[indice][1]), 0)][1], 178 | 0.7 * potenza_nominale[max(12 - round(temperatura_esterna[indice][1]), 0)][1], 179 | potenza_termica_corrente, 180 | potenza_nominale[max(12 - round(temperatura_esterna[indice][1]), 0)][2] 181 | ) 182 | ) 183 | indice += 1 184 | 185 | #logger.info ("Energia termica effettiva = %2.1f kWh" % energia_termica_actual) 186 | # INIZIALIZZAZIONE VARIABILI CONTROLLER PI 187 | 188 | Integrale = 0.0 189 | 190 | # LOOP PRINCIPALE 191 | 192 | temperatura_esterna_last = -1000.0 193 | modo_operativo_last = 0.0 194 | mode_last = 0.0 195 | temperatura_mandata_nominale_round_last = 0.0 196 | temperatura_mandata_nominale_last = 0.0 197 | temperatura_mandata = 0.0 198 | temperatura_mandata_last = 0.0 199 | 200 | while (1): 201 | 202 | errore_lettura = False 203 | 204 | # APERTURA CONNESSIONE CAN BUS 205 | 206 | try: 207 | bus = can.interface.Bus(channel='can0', bustype='socketcan_native') 208 | except Exception: 209 | print ("exception open bus") 210 | sys.exit(0) 211 | 212 | # legge modo operativo corrente da HPSU 213 | 214 | if (errore_lettura != True): 215 | command = com_leggi_modooperativo 216 | msg_data = [int(r, 16) for r in command.split(" ")] 217 | 218 | try: 219 | msg = can.Message(arbitration_id=receiver_id, data=msg_data, extended_id=False, dlc=7) 220 | bus.send(msg) 221 | except Exception: 222 | print('exception', 'Error sending msg') 223 | sys.exit(0) 224 | try: 225 | rcbus = bus.recv(1.0) 226 | except Exception: 227 | logger.error('exception', 'Error reading msg') 228 | sys.exit(0) 229 | 230 | modo_operativo = -10.0 231 | 232 | 233 | if rcbus and rcbus.data and (len(rcbus.data) >= 7) and (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]): 234 | modo_operativo = rcbus.data[5] 235 | 236 | # skippa dati sballati 237 | 238 | if (modo_operativo == -10.0): 239 | modo_operativo = modo_operativo_last 240 | errore_lettura = True 241 | logger.error ("HPSU : *** ERRORE LETTURA PARAMETRO MODO OPERATIVO CORRENTE ***") 242 | else: 243 | modo_operativo_last = modo_operativo 244 | 245 | # legge mode corrente da HPSU 246 | 247 | if (errore_lettura != True) and (modo_operativo == 3.0): 248 | command = com_leggi_mode 249 | msg_data = [int(r, 16) for r in command.split(" ")] 250 | 251 | try: 252 | msg = can.Message(arbitration_id=receiver_id, data=msg_data, extended_id=False, dlc=7) 253 | bus.send(msg) 254 | except Exception: 255 | print('exception', 'Error sending msg') 256 | sys.exit(0) 257 | try: 258 | rcbus = bus.recv(1.0) 259 | except Exception: 260 | print('exception', 'Error reading msg') 261 | sys.exit(0) 262 | 263 | mode = -10.0 264 | 265 | if rcbus and rcbus.data and (len(rcbus.data) >= 7) and (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]): 266 | mode = rcbus.data[6] 267 | 268 | # skippa dati sballati 269 | 270 | if (mode == -10.0): 271 | mode = mode_last 272 | errore_lettura = True 273 | logger.error ("HPSU : *** ERRORE LETTURA PARAMETRO MODE ***") 274 | else: 275 | mode_last = mode 276 | 277 | # legge temperatura ritorno corrente da HPSU 278 | 279 | if (errore_lettura != True) and (modo_operativo == 3.0): 280 | command = com_leggi_tritorno 281 | msg_data = [int(r, 16) for r in command.split(" ")] 282 | 283 | try: 284 | msg = can.Message(arbitration_id=receiver_id, data=msg_data, extended_id=False, dlc=7) 285 | bus.send(msg) 286 | except can.CanError: 287 | logger.error('exception', 'Error sending msg') 288 | sys.exit(0) 289 | try: 290 | rcbus = bus.recv(1.0) 291 | except can.CanError: 292 | logger.error('exception', 'Error reading msg') 293 | sys.exit(0) 294 | 295 | temperatura_ritorno = 0.0 296 | 297 | if rcbus and rcbus.data and (len(rcbus.data) >= 7) and (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]): 298 | temperatura_ritorno = (rcbus.data[6] + rcbus.data[5] * 256) / 10.0 299 | 300 | # skippa e filtra dati sballati 301 | 302 | if (temperatura_ritorno <= 15.0): 303 | temperatura_ritorno = 26.0 304 | errore_lettura = True 305 | logger.error ("HPSU : *** ERRORE LETTURA PARAMETRO TEMPERATURA RITORNO ***") 306 | else: 307 | # se il valore letto e' valido, faccio la media mobile sugli ultimi 4 campioni 308 | temperatura_ritorno = get_smooth(temperatura_ritorno) 309 | 310 | # legge temperatura esterna corrente da HPSU 311 | 312 | if (errore_lettura != True) and (modo_operativo == 3.0): 313 | command = com_leggi_testerna 314 | msg_data = [int(r, 16) for r in command.split(" ")] 315 | 316 | try: 317 | msg = can.Message(arbitration_id=receiver_id, data=msg_data, extended_id=False, dlc=7) 318 | bus.send(msg) 319 | except Exception: 320 | print('exception', 'Error sending msg') 321 | sys.exit(0) 322 | try: 323 | rcbus = bus.recv(1.0) 324 | except Exception: 325 | print('exception', 'Error reading msg') 326 | sys.exit(0) 327 | 328 | temperatura_esterna = -1000.0 329 | 330 | if rcbus and rcbus.data and (len(rcbus.data) >= 7) and (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]): 331 | temperatura_esterna = (rcbus.data[6] + rcbus.data[5] * 256) / 10.0 332 | 333 | # skippa dati sballati 334 | 335 | if ((temperatura_esterna < -20.0) or (temperatura_esterna > 45.0)): 336 | temperatura_esterna = temperatura_esterna_last 337 | errore_lettura = True 338 | logger.error ("HPSU : *** ERRORE LETTURA PARAMETRO TEMPERATURA ESTERNA ***") 339 | else: 340 | if (temperatura_esterna_last != -1000.0): 341 | temperatura_esterna = (temperatura_esterna + temperatura_esterna_last) / 2.0 342 | temperatura_esterna_last = temperatura_esterna 343 | 344 | # legge temperatura mandata corrente da HPSU 345 | 346 | if (errore_lettura != True) and (modo_operativo == 3.0): 347 | command = com_leggi_tmandata 348 | msg_data = [int(r, 16) for r in command.split(" ")] 349 | 350 | try: 351 | msg = can.Message(arbitration_id=receiver_id, data=msg_data, extended_id=False, dlc=7) 352 | bus.send(msg) 353 | except Exception: 354 | print('exception', 'Error sending msg') 355 | sys.exit(0) 356 | try: 357 | rcbus = bus.recv(1.0) 358 | except Exception: 359 | print('exception', 'Error reading msg') 360 | sys.exit(0) 361 | 362 | temperatura_mandata = 0.0 363 | 364 | if rcbus and rcbus.data and (len(rcbus.data) >= 7) and (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]): 365 | temperatura_mandata = (rcbus.data[4] + rcbus.data[3] * 256) / 10.0 366 | 367 | # skippa dati sballati 368 | 369 | if ((temperatura_mandata < 15.0) or (temperatura_mandata > 60.0)): 370 | temperatura_mandata = temperatura_mandata_last 371 | errore_lettura = True 372 | logger.error ("HPSU : *** ERRORE LETTURA PARAMETRO TEMPERATURA MANDATA ***") 373 | else: 374 | temperatura_mandata = get_smooth_flow(temperatura_mandata) 375 | temperatura_mandata_last = temperatura_mandata 376 | 377 | # RECUPERA LA TEMPERATURA INTERNA DA OEM 378 | 379 | if (errore_lettura != True) and (modo_operativo == 3.0): 380 | OEM_API_KEY = 'f7f5d003c595ed3285cd616521aa5aab' 381 | OEM_APIURL = 'http://emoncms.org/feed/value.json?id=36238&apikey=' + OEM_API_KEY 382 | 383 | try: 384 | r = requests.get(OEM_APIURL, timeout=5) 385 | except: 386 | errore_lettura = True 387 | logger.error(requests.exceptions.RequestException) 388 | 389 | if r.status_code != 200: 390 | logger.error ("Error:", r.status_code) 391 | else: 392 | json_temperature = r.json() 393 | temperatura_interna = float(json_temperature) 394 | logger.info ("OEM : T Int = %02.1f C" % temperatura_interna) 395 | 396 | # faccio l'elaborazione solo se la HPSU e' in modalita' riscaldamento e non ci sono stati errori tecnici di lettura dei dati 397 | if (errore_lettura != True) and (modo_operativo == 3.0): 398 | 399 | # calcola i limiti di potenza termica (e Delta T) alla temperatura esterna corrente 400 | potenza_nominale_100 = potenza_nominale[max(12 - round(temperatura_esterna),0)][1] 401 | potenza_nominale_30 = 0.30 * potenza_nominale_100 402 | potenza_nominale_70 = 0.70 * potenza_nominale_100 403 | logger.info("HPSU : TA = %02.1f C => P Nom (kW) @30%% = %02.2f @70%% = %02.2f @100%% = %02.2f" % (temperatura_esterna, potenza_nominale_30, potenza_nominale_70, potenza_nominale_100)) 404 | 405 | # applico sia i limiti di potenza che il limite di Delta T compreso tra 3 ed 8 gradi 406 | # ho alzato arbitrariamente il valore minimo a 3.5 C 407 | delta_t_minimo = max(potenza_nominale_30 / (1.163 * portata) * 1000.0, 1.5) 408 | delta_t_massimo = min(potenza_nominale_70 / (1.163 * portata) * 1000.0, 8.0) 409 | logger.info("HPSU : TA = %02.1f C => Delta T (C) @30%% = %02.2f @70%% = %02.2f" % (temperatura_esterna, delta_t_minimo, delta_t_massimo)) 410 | 411 | # verifica di non essere in modalita' corrente raffrescamento 412 | if ((mode == 0.0) or (mode == 1.0) or (mode == 3.0) or (mode == 4.0)) : 413 | 414 | # inizio elaborazione controller PI 415 | Errore = temperatura_interna_nominale - temperatura_interna 416 | if (Errore > 5.0) or (Errore < -5.0) : 417 | logger.error ("ERRORE TROPPO GRANDE !!!") 418 | sys.exit(0) 419 | 420 | # aggiorno l'integrale del controller PI solo se c'e' comando di compressore acceso 421 | if (mode == 1.0): 422 | Integrale += Errore * Dt 423 | OutputPI = Kp * Errore + Ki * Integrale 424 | 425 | # centro il controller PI sul valore atteso di potenza termica data la previsione di temperatura esterna, fabbisogno termico, numero ore di funzionamento 426 | delta_t = 1000.0 * potenza_termica / (1.163 * portata) + (delta_t_massimo - delta_t_minimo) * OutputPI 427 | 428 | # verifico che il DeltaT stimato sia all'interno dei limiti calcolati in precedenza 429 | delta_t = min(max(delta_t_minimo, delta_t), delta_t_massimo) 430 | 431 | logger.info ("CONTROLLER PI : Integrale = %9.1f ; Errore = %1.2f ; Output PI = %1.6f ; Delta T nom = %2.2f (C) ; Delta T teo = %2.2f (C)" % (Integrale, Errore, OutputPI, delta_t, 1000.0 * potenza_termica / (1.163 * portata))) 432 | 433 | # sono con richiesta riscaldamento 434 | if (mode == 1.0): 435 | if (temperatura_mandata - temperatura_ritorno < 1.5): 436 | temperatura_mandata_nominale = temperatura_ritorno + 6.0 437 | else: 438 | temperatura_mandata_nominale = temperatura_ritorno + delta_t 439 | # evito di far spegnere il compressore 440 | temperatura_mandata_nominale = min(temperatura_mandata_nominale, temperatura_mandata + 0.75) 441 | temperatura_mandata_nominale = max (temperatura_mandata_nominale, temperatura_mandata - 0.75) 442 | else: 443 | temperatura_mandata_nominale = temperatura_ritorno + 6.0 444 | 445 | # limito la temperatura di mandata nominale calcolata ad un valore massimo di 35.0 C 446 | temperatura_mandata_nominale = min(temperatura_mandata_nominale, 35.0) 447 | 448 | temperatura_mandata_nominale_round = round ((temperatura_mandata_nominale) * 2.0)/ 2.0 449 | 450 | # smorzo le variazioni repentine di mandata nominale per evitare di far spegnere subito il compressore(solo quando sono entro i limiti di funzionamento della pompa di calore) 451 | if ((mode == 1.0) and (temperatura_mandata_nominale_round_last != 0.0) and ((temperatura_mandata_nominale_round - temperatura_ritorno) <= delta_t_massimo)): 452 | temperatura_mandata_nominale_round = min(max(temperatura_mandata_nominale_round, temperatura_mandata_nominale_round_last - 1.0), temperatura_mandata_nominale_round_last + 1.0) 453 | 454 | logger.info ("CONTROLLER PI + HPSU : TR = %02.1f C ; T-HC = %02.1f C ; T-HC Set = %2.2f C" % (temperatura_ritorno, temperatura_mandata, temperatura_mandata_nominale_round)) 455 | 456 | if ((temperatura_mandata_nominale_round_last == 0.0) or 457 | (temperatura_mandata_nominale_round != temperatura_mandata_nominale_round_last)): 458 | intero = int (temperatura_mandata_nominale_round * 10) 459 | #print ("gino", intero) 460 | alto = intero >> 8 461 | basso = intero & 255 462 | #print (alto, basso) 463 | tempHex = "%02x %02x" % (alto, basso) 464 | 465 | #print (tempHex) 466 | 467 | command = com_scrivi_mandata % tempHex 468 | 469 | #print (command) 470 | 471 | msg_data = [int(r, 16) for r in command.split(" ")] 472 | 473 | try: 474 | msg = can.Message(arbitration_id=receiver_id, data=msg_data, extended_id=False, dlc=7) 475 | bus.send(msg) 476 | except Exception: 477 | print('exception', 'Error sending msg') 478 | sys.exit(0) 479 | 480 | logger.info ("CONTROLLER PI + HPSU : Modo Oper. = %01.0f ; Mode = %01.0f ; TR = %02.1f C ; Changing T-HC Setpoint from %2.2f to %2.2f C (would be %2.2f C)" % (modo_operativo, mode, temperatura_ritorno, temperatura_mandata_nominale_round_last, temperatura_mandata_nominale_round, temperatura_mandata_nominale)) 481 | 482 | temperatura_mandata_nominale_round_last = temperatura_mandata_nominale_round 483 | else: 484 | logger.info ("CONTROLLER PI + HPSU : Modo Oper. = %01.0f ; Mode = %01.0f ; TR = %02.1f C" % (modo_operativo, mode, temperatura_ritorno)) 485 | 486 | else: 487 | logger.info ("CONTROLLER PI + HPSU : Modo Oper. = %01.0f ; Mode = %01.0f ; TR = %02.1f C" % (modo_operativo, mode, temperatura_ritorno)) 488 | 489 | #print("alive") 490 | time.sleep(40) 491 | else: 492 | if (errore_lettura != True): 493 | logger.error ("HPSU : MODALITA' RISCALDAMENTO OFF") 494 | # non essendo in modalita' riscaldamento richiesto allunga la finestra di controllo dello stato 495 | time.sleep(300) 496 | else: 497 | #logger.error ("CONTROLLER PI + HPSU : *** ERRORE LETTURA DA HPSU ***") 498 | time.sleep(3) 499 | -------------------------------------------------------------------------------- /contrib/control/README.md: -------------------------------------------------------------------------------- 1 | # Control Scripts 2 | Scripts to automatically control HPSU. 3 | ## Chrono-thermostat 4 | 5 | Set of useful scripts to automatically control: 6 | * heating/cooling timeframe 7 | * heating/cooling setpoints 8 | 9 | ## Flow Temperature Control 10 | 11 | Scripts to control heating flow temperature: 12 | * PI Controller (inside temperature vs setpoint) 13 | * heating power control within HPSU specifications 14 | 15 | ## Operating Mode / Setpoints Scheduling 16 | 17 | * Scripts to schedule HPSU Operating Mode settings 18 | * Scripts to schedule Cooling/DHW/Heating setpoints settings 19 | * Crontab example 20 | 21 | ## To-do list 22 | - [ ] Make all configuration parameters external 23 | - [ ] Include DHW control inside chrono-thermostat (currently in crontab) 24 | - [ ] Create cooling flow temperature control (nice to have) 25 | - [ ] Create smarter DHW setpoint temperature control (nice to have) 26 | -------------------------------------------------------------------------------- /contrib/control/Setpoint-Mode/README.md: -------------------------------------------------------------------------------- 1 | # Operating Mode / Setpoints Scheduling 2 | 3 | * Scripts to schedule HPSU Operating Mode changes: 4 | * Summer Mode `setmode_Estate.py` 5 | * Cooling Mode `setmode_Raffrescare.py` 6 | * Heating Mode `setmode_Riscaldare.py` 7 | 8 | * Scripts to schedule Cooling/DHW/Heating setpoints settings: 9 | * Cooling Setpoint `set_T-ImpRefrig.py` 10 | * DHW Setpoint `set_T-ACS1.py` 11 | * DHW Hysteresis `set_IsteresiACS.py` 12 | * Heating Setpoint `set_T-Ambiente1.py` 13 | 14 | * Crontab example `crontab-sample` 15 | -------------------------------------------------------------------------------- /contrib/control/Setpoint-Mode/crontab-sample: -------------------------------------------------------------------------------- 1 | # m h dom mon dow command 2 | 00 20 * * * python3 /home/pi/pyHPSU-master/set_IsteresiACS.py 20 3 | 01 20 * * * python3 /home/pi/pyHPSU-master/set_T-ACS1.py 480 4 | 31 22 * * * python3 /home/pi/pyHPSU-master/set_T-ACS1.py 440 5 | 00 00 * * * python3 /home/pi/pyHPSU-master/set_IsteresiACS.py 30 6 | 01 00 * * * python3 /home/pi/pyHPSU-master/set_T-ACS1.py 420 7 | 00 19 * * * python3 /home/pi/pyHPSU-master/set_T-ImpRefrig.py 210 8 | 30 19 * * * python3 /home/pi/pyHPSU-master/set_T-ImpRefrig.py 200 9 | 30 20 * * * python3 /home/pi/pyHPSU-master/set_T-ImpRefrig.py 190 10 | 00 22 * * * python3 /home/pi/pyHPSU-master/set_T-ImpRefrig.py 180 11 | 00 00 * * * python3 /home/pi/pyHPSU-master/set_T-ImpRefrig.py 170 12 | 03 02 * * * python3 /home/pi/pyHPSU-master/set_T-ImpRefrig.py 160 13 | 03 05 * * * python3 /home/pi/pyHPSU-master/set_T-ImpRefrig.py 180 14 | -------------------------------------------------------------------------------- /contrib/control/Setpoint-Mode/set_IsteresiACS.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys, time 5 | try: 6 | import can 7 | except Exception: 8 | pass 9 | 10 | if __name__ == "__main__": 11 | temp = sys.argv[1:] 12 | if len(temp) == 0: 13 | print("passare temperatura su command line in formato 'gradi * 10', esempio 210 = 21,0 gradi") 14 | sys.exit(0) 15 | 16 | #if int(temp[0]) < 100: 17 | # print("sicuro che stai passando la temperatura moltiplicata 10???? 210 = 21 gradi!!! Emiliano ocio!") 18 | # sys.exit(0) 19 | intero = int(temp[0]) 20 | #print (intero) 21 | alto = intero >> 8 22 | basso = intero & 255 23 | #print (alto, basso) 24 | tempHex = "%02x %02x" % (alto, basso) 25 | 26 | #print (tempHex) 27 | 28 | #command = "30 00 fa 06 91 %s" % tempHex 29 | command = "32 00 fa 06 91 %s" % tempHex 30 | 31 | #print (command) 32 | 33 | id = "680" #provare con 11a? oppure 190? oppure 310? 34 | 35 | receiver_id = int(id, 16) 36 | msg_data = [int(r, 16) for r in command.split(" ")] 37 | 38 | try: 39 | bus = can.interface.Bus(channel='can0', bustype='socketcan_native') 40 | except Exception: 41 | print ("exception open bus") 42 | sys.exit(0) 43 | 44 | try: 45 | msg = can.Message(arbitration_id=receiver_id, data=msg_data, extended_id=False, dlc=7) 46 | bus.send(msg) 47 | except Exception: 48 | print('exception', 'Error sending msg') 49 | sys.exit(0) 50 | 51 | -------------------------------------------------------------------------------- /contrib/control/Setpoint-Mode/set_T-ACS1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys, time 5 | try: 6 | import can 7 | except Exception: 8 | pass 9 | 10 | if __name__ == "__main__": 11 | temp = sys.argv[1:] 12 | if len(temp) == 0: 13 | print("passare temperatura su command line in formato 'gradi * 10', esempio 210 = 21,0 gradi") 14 | sys.exit(0) 15 | 16 | if int(temp[0]) < 100: 17 | print("sicuro che stai passando la temperatura moltiplicata 10???? 210 = 21 gradi!!! Emiliano ocio!") 18 | sys.exit(0) 19 | intero = int(temp[0]) 20 | #print (intero) 21 | alto = intero >> 8 22 | basso = intero & 255 23 | #print (alto, basso) 24 | tempHex = "%02x %02x" % (alto, basso) 25 | 26 | #print (tempHex) 27 | 28 | #command = "30 00 13 %s 00 00" % tempHex 29 | command = "32 00 fa 00 13 %s" % tempHex 30 | 31 | #print (command) 32 | 33 | id = "680" #provare con 11a? oppure 190? oppure 310? 34 | 35 | receiver_id = int(id, 16) 36 | msg_data = [int(r, 16) for r in command.split(" ")] 37 | 38 | try: 39 | bus = can.interface.Bus(channel='can0', bustype='socketcan_native') 40 | except Exception: 41 | print ("exception open bus") 42 | sys.exit(0) 43 | 44 | try: 45 | msg = can.Message(arbitration_id=receiver_id, data=msg_data, extended_id=False, dlc=7) 46 | bus.send(msg) 47 | except Exception: 48 | print('exception', 'Error sending msg') 49 | sys.exit(0) 50 | 51 | -------------------------------------------------------------------------------- /contrib/control/Setpoint-Mode/set_T-Ambiente1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys, time 5 | try: 6 | import can 7 | except Exception: 8 | pass 9 | 10 | if __name__ == "__main__": 11 | temp = sys.argv[1:] 12 | if len(temp) == 0: 13 | print("passare temperatura su command line in formato 'gradi * 10', esempio 210 = 21,0 gradi") 14 | sys.exit(0) 15 | 16 | if int(temp[0]) < 100: 17 | print("sicuro che stai passando la temperatura moltiplicata 10???? 210 = 21 gradi!!! Emiliano ocio!") 18 | sys.exit(0) 19 | intero = int(temp[0]) 20 | #print (intero) 21 | alto = intero >> 8 22 | basso = intero & 255 23 | #print (alto, basso) 24 | tempHex = "%02x %02x" % (alto, basso) 25 | 26 | #print (tempHex) 27 | 28 | #command = "62 00 05 00 %s 00 00" % tempHex 29 | #command = "62 00 05 00 %s 00 00" % tempHex 30 | #command = "62 0a 05 00 %s 00 00" % tempHex 31 | #command = "60 0a 05 00 %s 00 00" % tempHex 32 | command = "32 00 FA 00 05 %s 00" % tempHex 33 | 34 | #print (command) 35 | 36 | id = "680" #provare con 11a? oppure 190? oppure 310? 37 | 38 | receiver_id = int(id, 16) 39 | msg_data = [int(r, 16) for r in command.split(" ")] 40 | 41 | try: 42 | bus = can.interface.Bus(channel='can0', bustype='socketcan_native') 43 | except Exception: 44 | print ("exception open bus") 45 | sys.exit(0) 46 | 47 | try: 48 | msg = can.Message(arbitration_id=receiver_id, data=msg_data, extended_id=False, dlc=7) 49 | bus.send(msg) 50 | except Exception: 51 | print('exception', 'Error sending msg') 52 | sys.exit(0) 53 | 54 | -------------------------------------------------------------------------------- /contrib/control/Setpoint-Mode/set_T-ImpRefrig.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys, time 5 | try: 6 | import can 7 | except Exception: 8 | pass 9 | 10 | if __name__ == "__main__": 11 | temp = sys.argv[1:] 12 | if len(temp) == 0: 13 | print("passare temperatura su command line in formato 'gradi * 10', esempio 210 = 21,0 gradi") 14 | sys.exit(0) 15 | 16 | if int(temp[0]) < 100: 17 | print("sicuro che stai passando la temperatura moltiplicata 10???? 210 = 21 gradi!!! Emiliano ocio!") 18 | sys.exit(0) 19 | intero = int(temp[0]) 20 | print (intero) 21 | alto = intero >> 8 22 | basso = intero & 255 23 | print (alto, basso) 24 | tempHex = "%02x %02x" % (alto, basso) 25 | 26 | print (tempHex) 27 | 28 | command = "32 00 FA 03 DD %s" % tempHex 29 | 30 | print (command) 31 | 32 | #sys.exit(0) 33 | 34 | id = "680" #provare con 11a? oppure 190? oppure 310? 35 | 36 | receiver_id = int(id, 16) 37 | msg_data = [int(r, 16) for r in command.split(" ")] 38 | 39 | try: 40 | bus = can.interface.Bus(channel='can0', bustype='socketcan_native') 41 | except Exception: 42 | print ("exception open bus") 43 | sys.exit(0) 44 | 45 | try: 46 | msg = can.Message(arbitration_id=receiver_id, data=msg_data, extended_id=False, dlc=7) 47 | bus.send(msg) 48 | except Exception: 49 | print('exception', 'Error sending msg') 50 | sys.exit(0) 51 | 52 | -------------------------------------------------------------------------------- /contrib/control/Setpoint-Mode/setmode_Estate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys, time 5 | try: 6 | import can 7 | except Exception: 8 | pass 9 | 10 | if __name__ == "__main__": 11 | 12 | # 01 - Standby 13 | # 11 - Raffreddare 14 | # 04 - Ridurre 15 | # 03 - Riscaldare 16 | # 05 - Estate 17 | # 0b - Automatico 1 18 | # 0c - Automatico 2 19 | 20 | command = "32 00 FA 01 12 05 00" 21 | 22 | id = "680" 23 | 24 | receiver_id = int(id, 16) 25 | msg_data = [int(r, 16) for r in command.split(" ")] 26 | 27 | try: 28 | bus = can.interface.Bus(channel='can0', bustype='socketcan_native') 29 | except Exception: 30 | print ("exception open bus") 31 | sys.exit(0) 32 | 33 | try: 34 | msg = can.Message(arbitration_id=receiver_id, data=msg_data, extended_id=False, dlc=7) 35 | bus.send(msg) 36 | except Exception: 37 | print('exception', 'Error sending msg') 38 | sys.exit(0) 39 | 40 | -------------------------------------------------------------------------------- /contrib/control/Setpoint-Mode/setmode_Raffrescare.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys, time 5 | try: 6 | import can 7 | except Exception: 8 | pass 9 | 10 | if __name__ == "__main__": 11 | 12 | # 01 - Standby 13 | # 11 - Raffreddare 14 | # 04 - Ridurre 15 | # 03 - Riscaldare 16 | # 05 - Estate 17 | # 0b - Automatico 1 18 | # 0c - Automatico 2 19 | 20 | command = "32 00 FA 01 12 11 00" 21 | 22 | id = "680" 23 | 24 | receiver_id = int(id, 16) 25 | msg_data = [int(r, 16) for r in command.split(" ")] 26 | 27 | try: 28 | bus = can.interface.Bus(channel='can0', bustype='socketcan_native') 29 | except Exception: 30 | print ("exception open bus") 31 | sys.exit(0) 32 | 33 | try: 34 | msg = can.Message(arbitration_id=receiver_id, data=msg_data, extended_id=False, dlc=7) 35 | bus.send(msg) 36 | except Exception: 37 | print('exception', 'Error sending msg') 38 | sys.exit(0) 39 | 40 | -------------------------------------------------------------------------------- /contrib/control/Setpoint-Mode/setmode_Riscaldare.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys, time 5 | try: 6 | import can 7 | except Exception: 8 | pass 9 | 10 | if __name__ == "__main__": 11 | 12 | # 01 - Standby 13 | # 11 - Raffreddare 14 | # 04 - Ridurre 15 | # 03 - Riscaldare 16 | # 05 - Estate 17 | # 0b - Automatico 1 18 | # 0c - Automatico 2 19 | 20 | command = "32 00 FA 01 12 03 00" 21 | 22 | id = "680" 23 | 24 | receiver_id = int(id, 16) 25 | msg_data = [int(r, 16) for r in command.split(" ")] 26 | 27 | try: 28 | bus = can.interface.Bus(channel='can0', bustype='socketcan_native') 29 | except Exception: 30 | print ("exception open bus") 31 | sys.exit(0) 32 | 33 | try: 34 | msg = can.Message(arbitration_id=receiver_id, data=msg_data, extended_id=False, dlc=7) 35 | bus.send(msg) 36 | except Exception: 37 | print('exception', 'Error sending msg') 38 | sys.exit(0) 39 | 40 | -------------------------------------------------------------------------------- /contrib/hpsud_service_sample.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Spanni26/pyHPSU/14e784b222da5957df2cd5a9282d1534ffaf7ab7/contrib/hpsud_service_sample.7z -------------------------------------------------------------------------------- /etc/pyHPSU/commands_hpsu_DE.csv: -------------------------------------------------------------------------------- 1 | name;label;description 2 | t_hs;T-WE;Angezeigt wird die aktuelle Vorlauftemperatur (TVBH) des Waermeerzeugers in C. 3 | t_hs_set;T-WE Soll;Angezeigt wird die aktuelle Vorlauf-Solltemperatur des Waermeerzeugers in C 4 | water_pressure;Wasserdruck;Angezeigt wird der aktuelle Wasserdruck in bar. 5 | t_ext;T-Aussen;Angezeigt wird die gemittelte Aussentemperatur in C. 6 | t_dhw;T-WW;Angezeigt wird die aktuelle Temperatur des Warmwasserspeichers in C. Sollte keine Warmwasserfunktion aktiviert sein, wird --- angezeigt. 7 | t_dhw_set;T-WW Soll;aktuelle Warmwasser-Solltemperatur in C. Sollte keine Warmwasserfunktion aktiviert sein, wird --- angezeigt. Der aktuelle Sollwert ist hier immer der Maximalwert aller fuer diesen Warmwasserkreis relevanten Anforderungen. 8 | t_return;T-Ruecklauf;Angezeigt wird die aktuelle Ruecklauftemperatur des Waermeerzeugers in C. Ist kein entsprechender Sensor am Waermeerzeuger angeschlossen, wird --- angezeigt. 9 | flow_rate;Durchfluss;Angezeigt wird der gefilterte Wert des aktuellen Volumenstroms in Liter pro Stunde. 10 | t_hc;T-HK;Angezeigt wird die Vorlauftemperatur des direkten Heizkreises in C. 11 | t_hc_set;T-HK Soll;Angezeigt wird die Vorlauf-Solltemperatur des direkten Heizkreises in C. 12 | status_pump;Status Kesselpumpe;Angezeigt wird der aktuelle Status der internen Heizungsumwaelzpumpe der ROTEX HPSU compact. 13 | runtime_comp;Laufzeit Kompr;Angezeigt wird die Laufzeit des Kuehltemittelverdichters in h. 14 | runtime_pump;Laufzeit Pumpe;Angezeigt wird die Laufzeit der internen Heizungsumwaelzpumpe in h. 15 | posmix;Mischer Positiion;aktuelle Stellung des 3-Wege-Umschaltventils 3UV DHW. 0 %: Stellung A (Raumheizung) 100 %: Stellung B (Warmwasserbereitung) 16 | qboh;EHS fuer DHW;Angezeigt wird die Waermemenge des zusaetzlichen Waermeerzeugers fuer die Warmwasserbereitung in kWh. 17 | qchhp;EHS fuer CH;Angezeigt wird die Waermemenge des zusaetzlichen Waermeerzeugers fuer den Heizbetrieb in kWh. 18 | qsc;Energie Kuehlung;Angezeigt wird die Waermemenge der Waermepumpe fuer den Kuehlbetrieb in kWh. 19 | qch;Energie Heizung;Angezeigt wird die Waermemenge der Waermepumpe fuer den Heizbetrieb in kWh. 20 | qwp;Energie erzeugt;Angezeigt wird die gesamte Waermemenge der Waermepumpe in kWh. 21 | qdhw;Energie fuer WW;Angezeigt wird die Waermemenge fuer die Warmwasserbereitung in kWh. 22 | sw_vers_01;Version SW 1;Software Version 1 23 | sw_vers_02;Version SW 2;Software Version 2 24 | sw_vers_03;Version SW 3;Software version 3 25 | mode_01;Modus;Modus Rotex 26 | tvbh2;TVBH2 [C];Aktuelle Temperatur Heizung Vorlauf ggf. nach Heizungsunterstuetzungswaermetauscher (tV,BH). 27 | tliq2;Tliq2 [C];Aktuelle Kältemitteltemperatur (tliq2). 28 | tr2;TR2 [C];Aktuelle Temperatur Heizung Ruecklauf, sekundaerer Fuehler (tR2). 29 | ta2;TA2 [C];Aktuelle Aussentemperatur (gemessen von Temperaturfuehler des Waermepumpenaussengeraets) 30 | tdhw2;Tdhw2 [C];Current temperature in domestic hot water storage tank, secondary sensor (tDHW2). 31 | quiet;quiet;Shows the status of the whisper mode. 32 | mode;Modus;Aktueller Modus der Wärmepumpe: ---: No heating or cooling demand : Heating : Cooling : Domestic hot water generation : Automatic defrosting function active 33 | pump;Pump;Aktuelle Leistung der internen Heizungsumwälzpumpe in % 34 | ext;Ext;Aktueller Energiemodus der Wärmepumpe: LT: EVU-Funktion HT/NT aktiv und Niedertarif. HT: EVU-Funktion HT/NT aktiv und Hochtarif. SGN: EVU-Funktion SMART GRID aktiv, Normalbetrieb. SG1: EVU-Funktion SMART GRID aktiv, Abwurf: kein Wärmepumpenbetrieb, keine Frostschutzfunktion. SG2: EVU-Funktion SMART GRID aktiv, Einschaltempfehlung, Betrieb mit höheren Solltemperaturen, billiger Strom. SG3:EVU-Funktion SMART GRID aktiv, Einschaltbefehl und Speicherladung auf 70 °C, billiger Strom. - - -: Kein externer Modus aktiv, Wärmepumpe arbeitet im normalen Betrieb. 35 | ehs;EHS;Aktuelle Leistung des Backup-Heaters in kW 36 | rt;RT;Parameter [Room thermostat] / [Interlink fct] 37 | bpv;BPV;Aktuelle Position Mischventil 3UVB1 (100% = A, 0% = B) 38 | t_v1;TV;Aktuelle Vorlauftemperatur nach dem Plattenwaermetauscher (tV1) 39 | t_dhw1;Tdhw;Aktuelle Temperatur im Warmwasserspeicher (tDHW1) 40 | t_vbh;TVBH;Aktuelle Temperatur Heizung Vorlauf ggf. nach Heizungsunterstuetzungswaermetauscher (tV,BH) 41 | t_outdoor_ot1;TA;Aktuelle Aussentemperatur (gemessen von optionalem Temperaturfuehler RoCon OT1) 42 | t_r1;TR;Aktuelle Temperatur Heizung Ruecklauf (tR1) 43 | v1;V;Aktueller Volumenstrom (Durchfluss) in der Heizungsanlage 44 | t_room1_setpoint;T Room 1 Setpoint; Setpoint 1 value 45 | t_room2_setpoint;T Room 2 Setpoint; Setpoint 2 value 46 | t_room3_setpoint;T Room 3 Setpoint; Setpoint 3 value 47 | heat_slope;Heizkurve;Heizkurve 48 | t_dhw_setpoint1;T-WW Soll 1;Sollwert der Warmwassertemperatur in Grad C, welche fuer den 1. Schaltzeitzyklus der Zeitprogramme [Automatik 1] und [Automatik 2] gilt 49 | t_dhw_setpoint2;T-WW Soll 1;Sollwert der Warmwassertemperatur in Grad C, welche fuer den 2. Schaltzeitzyklus der Zeitprogramme [Automatik 1] und [Automatik 2] gilt 50 | t_dhw_setpoint3;T-WW Soll 1;Sollwert der Warmwassertemperatur in Grad C, welche fuer den 3. Schaltzeitzyklus der Zeitprogramme [Automatik 1] und [Automatik 2] gilt 51 | hyst_hp;Hysterese WW; Einstellung der Hysterese fuer die Warmwasserbereitung. Die Warmwasserbereitung wird aktiviert, wenn die am Warmwasserfuehler gemessene Temperatur unter die aktuelle Warmwasser-Solltemperatur minus dem hier eingestellten Wert liegt. Eine Warmwasserbereitung istbeendet, wenn die am Warmwasserfuehler gemessene Temperatur ueber der aktuellen Warmwasser-Solltemperatur liegt 52 | t_flow_cooling;T-Flow Kuehlung;T-Flow Kühlung 53 | error;Fehler;Fehlercodename 54 | outdoor_type;Aussengerät;Typ Wärmepumpenaußengerät 55 | indoor_unit;Innengerät;Typ Wärmepumpeninnengerät 56 | func_heating;Funktion EHS;Einstellung ob zusätzlicher Wärmeerzeuger (WEZ) für Warmwasserbereitung und Heizungsunterstützung vorhanden ist 57 | hzu;HZ Unterstützung;Heizungsunterstützung aus Warmwasserspeicher, wenn Mindesttemperatur überschritten ist 58 | equi_func;Bivalenzfunktion;Die Bivalenzfunktion ist für den Betrieb des optionalen Zuheizers aufgrund einer Backup-Anforderung (Raumheizbetrieb) relevant. 59 | smart_grid;SMART GRID;Auswertung des SG-Signals 60 | modus_sg;Modus SG;Nur wenn Parameter [SMART GRID] = 1: Dient zu einer möglichen Soll-Temperaturerhöhung bei einem SMART GRID-Einschaltbefehl 61 | ht_nt_func;HT/NT Funktion;Einstellung, welche Wärmequellen ausgeschaltet werden, wenn bei einem Niedertarif-Netzanschluss das vom Energieversorgungsunternehmen (EVU) ausgegebene Signal für Hochtarif empfangen wird. 62 | ht_nt_contact;HT/NT Anschluss;Festlegung, ob der HT-/NT-Eingang als Öffner- oder Schließerkontakt ausgewertet wird 63 | room_therm;Raumthermostat;Konfiguration eines am Anschluss J16 der ROTEX HPSU compact angeschlossenen Raumthermostats mit potenzialfreien Kontakten 64 | interlink;Interlinkfunktion;Konfiguration für Anlagen, die mit 2 verschiedenen Vorlauf-Solltemperaturen betrieben werden 65 | air_purge;Entlüftungsfunktion;Aktivierung der automatischen Entlüftung der ROTEX HPSU compact und des angeschlossenen Heizkreislaufs 66 | max_perf_pump;Max Leistung Pumpe;Obergrenze für die Modulation der Pumpenleistung 67 | min_perf_pump;Min Leistung Pumpe;Untergrenze für die Modulation der Pumpenleistung 68 | outside_conf;SKonfig T-Aussen;Konfiguration des optionalen Außentemperaturfühlers RoCon OT1 69 | storage_conf;SKonfig T-WW;Konfiguration der Warmwasserbereitung 70 | pres_conf;SKonfig Druck;Konfiguration des Sensors zur Erfassung des Wasserdrucks der Anlage 71 | out_temp_adapt;AF Anpassung;Individuelle Anpassung für den Messwert der für die Regelung relevanten Außentemperatur 72 | power_dhw;Leistung WW;Wärmeleistung des elektrischen Zuheizers für Warmwasserbereitung 73 | buh_s1_pow;Leistung EHS Stufe 1;Wärmeleistung des elektrischen Zuheizers bei Heizungsunterstützung Stufe 1 74 | buh_s2_pow;Leistung EHS Stufe 2;Wärmeleistung des elektrischen Zuheizers bei Heizungsunterstützung Stufe 2 75 | power_biv;Leistung BIV;Einstellung begrenzt Leistung der Heizungsunterstützung 76 | tdiff_dhw_ch;TDiff-WW HZU;TDiff-WW HZU 77 | t_vbh1_max;Max Temp Heizung;Einstellung begrenzt die Vorlauf-Solltemperatur (gemessen an tV, BH) bei aktiver Heizungsunterstützungsfunktion 78 | equi_temp;Bivalenztemperatur;Einstellung beeinflusst die im Parameter [Sonderfkt Schaltk] definierte Wirkungsweise des potenzialfreien AUX-Schaltkontakts (Wechselschaltausgang A) 79 | quiet_mode;Flüsterbetrieb;Modus für geräuscharmen Betrieb bei reduzierter Leistung 80 | aux_fct;Sonderfkt Schaltk;Einstellung weist die Schaltbedingungen für den potenzialfreien AUX-Schaltkontakt zu 81 | aux_time;Wartezeit Sonderfkt;AUX-Schaltkontakt (A) schaltet erst verzögert, wenn die Schaltbedingung 82 | t_dhw_1_min;Schaltschwelle TDHW;Schaltschwelle Speichertemperatur (Tdhw) für AUX-Schaltkontakt 83 | delta_t_ch;Spreizung Mod HZ;Sollspreizung für Raumheizung. Die Heizungsumwälzpumpe der ROTEX HPSU compact regelt den Durchfluss, um die in dem Parameter hinterlegte Sollspreizung zwischen Vorlauf-Solltemperatur und Rücklauftemperatur (tV, BH - tR1), zu erreichen 84 | v_var;DurchflussBer;Aktuell benötigter Mindest-Volumenstrom der Anlage 85 | t_flow_ch_adj;Anpass T-VL Heizen;Nur wenn Parameter [Interlinkfunktion] = Ein. Vorlauf-Solltemperatur wird bei geschlossenem RT-Schaltkontakt Kühlen um den eingestellten Wert erhöht 86 | t_flow_cool_adj;Anpass T-VL Kühlen;Nur wenn Parameter [Interlinkfunktion] = Ein. Kühlvorlauf-Solltemperatur wird bei geschlossenem RT-Schaltkontakt Kühlen um den eingestellten Wert reduziert 87 | min_pressure;Min Druck;Definiert den minimalen Wasserdruck 88 | max_pressure;Max Druck;Definiert den maximalen Wasserdruck 89 | setpoint_pressure;Soll Druck;Definiert den Soll-Wasserdruck 90 | max_pressure_drop;Max Druckverlust;Definiert den maximal akzeptablen Druckverlust in der Heizungsanlage 91 | hc_func;HK Funktion;Einstellung definiert Art der Vorlauftemperaturregelung 92 | t_frost_protect;T-Frostschutz;Aus: Kein Frostschutz des Heizkreises Sonst: Wenn die Außentemperatur unter den eingestellten Wert sinkt, schaltet die Anlage in den Frostschutzbetrieb (Einschalten der Pumpen). Die Funktion wird beendet,wenn die Außentemperatur über den eingestellten Wert +1 K steigt 93 | insulation;Gebäudedämmung;Einstellung des Gebäudedämmstandards. Dadurch werden die gemittelte Außentemperatur und die automatischen Anpassungen der Heizkurve und der Heizzeiten beeinflusst 94 | screed;Estrich;Funktion zur Estrichtrocknung 95 | screed_day1;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 96 | screed_day2;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 97 | screed_day3;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 98 | screed_day4;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 99 | screed_day5;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 100 | screed_day6;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 101 | screed_day7;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 102 | screed_day8;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 103 | screed_day9;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 104 | screed_day10;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 105 | screed_day11;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 106 | screed_day12;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 107 | screed_day13;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 108 | screed_day14;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 109 | screed_day15;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 110 | screed_day16;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 111 | screed_day17;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 112 | screed_day18;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 113 | screed_day19;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 114 | screed_day20;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 115 | screed_day21;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 116 | screed_day22;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 117 | screed_day23;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 118 | screed_day24;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 119 | screed_day25;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 120 | screed_day26;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 121 | screed_day27;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 122 | screed_day28;Estrichprogramm;Einstellung des Ablaufprogramms der Estrichaufheizung. Für eine Dauer von maximal 28 Tagen kann separat für jeden Tag eine eigene Vorlauf-Solltemperatur eingestellt werden. Das Ende des Estrichprogramms wird durch den 1. Tag mit der Sollwerteinstellung „- - - -„ definiert 123 | t_out_lim_day;Heizgrenze Tag;Einstellung der automatischen Sommerabschaltung des Heizbetriebs 124 | t_out_lim_night;Heizgrenze Nacht;"Einstellung der Heizgrenze zur ""Abschaltung"" des Heizkreises während der Absenkzeit" 125 | t_flow_day;T-Vorlauf Tag;"Einstellung der Vorlauf-Solltemperatur für den Heizkreis während der Heizzeit bei Betriebsart: ""Automatik 1"", ""Automatik 2"", ""Heizen""" 126 | t_flow_night;T-Vorlauf Nacht;"Einstellung der Vorlauf-Solltemperatur für den Heizkreis während der Absenkzeit bei Betriebsart: ""Automatik 1"", ""Automatik 2"", ""Absenken""" 127 | max_t_flow;Max T-Vorlauf;Die ermittelte Vorlauf-Solltemperatur des Heizkreises wird auf den hier eingestellten Maximalwert begrenzt 128 | min_t_flow;Min T-Vorlauf;Die ermittelte Vorlauf-Solltemperatur des Heizkreises wird auf den hier eingestellten Minimalwert begrenzt 129 | hc_adapt;Heizk Adaption;Heizk Adaption 130 | start_tout_cool;Start Kühlen A-Temp;Einstellung, ab welcher Außentemperatur der Kühlbetrieb mit der höchsten Kühlvorlauf- Solltemperatur startet 131 | max_tout_cool;Max Kühlen A-Temp;Einstellung, bei welcher Außentemperatur die niedrigste Kühlvorlauf-Solltemperatur vorgegeben wird 132 | t_flow_cool_start;VL-Soll Start Kühlen;Einstellung der Kühlvorlauf-Solltemperatur beim Start des Kühlbetriebs 133 | t_flow_cool_max;VL-Soll Max Kühlen;Einstellung der minimalen Kühlvorlauf-Solltemperatur. Diese wird ab der Außentemperatur 134 | min_t_flow_cool;Min VL-Soll Kühlen;Einstellung der absoluten Untergrenze der Kühlvorlauf-Solltemperatur. Begrenzung wirkt, falls aus anderen Parametereinstellungen eine niedrigere Kühlvorlauf-Solltemperatur ermittelt würde 135 | t_flow_cool;T-VL Kühlen;Einstellung der Kühlvorlauf-Solltemperatur (Festwert) bei aktivem Kühlbetrieb 136 | cool_setpoint_adj;Kühlsollwert Korr;Parallelverschiebung der Kühl-Kennlinie um den eingestellten Wert 137 | circ_pump_dhw;Zirk mit WW-Prog;Einstellung zur Ansteuerung einer Zirkulationspumpe 138 | circ_pump_interval;Zirk Intervall;Einstellung der Intervallsteuerung für optionale Zirkulationspumpe 139 | anti_leg_day;Antileg Tag;Einstellung des Tages zur thermischen Desinfektion des Warmwasserspeichers 140 | anti_leg_time;Antileg Zeit;Einstellung der Startzeit der thermischen Desinfektion des Warmwasserspeichers 141 | anti_leg_temp;Antileg Temp;Einstellung der Warmwasser-Solltemperatur während der thermischen Desinfektion des Warmwasserspeichers 142 | max_dhw_loading;Max WW Ladezeit;Einstellung begrenzt den Zeitraum für die Warmwasserbereitung auf den eingestellten Sollwert 143 | dhw_off_time;WW Sperrzeit;Einstellung der Sperrzeit nach Abschluss oder Abbruch eines Warmwasserbereitungszyklus 144 | one_hot_water;1x Warmwasser;Start der einmaligen Aufheizung des Warmwassers auf den eingestellten Sollwert 145 | timer_boh;Wartezeit BOH;Verzögerungszeit, ab wann der zusätzliche Wärmeerzeuger die Wärmepumpe bei einer Warmwasserladung unterstützen darf 146 | t_reduced;T-Absenkung;Raum-Solltemperatur für die Absenkzeiten der permanenten Zeitprogramme [Automatik 1] und [Automatik 2] gilt 147 | t_absence;T-Abwesend;Raum-Solltemperatur für die Absenkzeiten der temporären Zeitprogramme [Abwesend] + [Urlaub] 148 | t_room; T-Raum;Raumtemperatur, die von einer optionalen Rocon U1 Raumstation gemessen wird 149 | -------------------------------------------------------------------------------- /etc/pyHPSU/commands_hpsu_EN.csv: -------------------------------------------------------------------------------- 1 | name;label;description 2 | t_hs;T-HS;The current temperature (TVBH) of the heat generator is displayed in C. 3 | t_hs_set;T-HS Setpoint;The current Inflow target temperature of the heat generator is displayed in C 4 | water_pressure;Water Pressure;The current water pressure is displayed in bar. 5 | t_ext;T-Outside;The average external temperature is displayed C. 6 | t_dhw;T-DHW;The current temperature of the hot water storage tank is displayed in C. If there is no hot water function activated, --- is displayed. 7 | t_dhw_set;T-DHW Setpoint;The current target hot water temperature is displayed in C. If there is no hot water function activated, --- is displayed. The current set value is here always the maximum value of all relevant demands for this hot water circuit 8 | t_return;T-Return;The current return flow temperature of the heat generator is displayed in C. If there is no relevant sensor connected to the heat generator, --- is displayed. 9 | flow_rate;Flow Rate;The filtered value of the current volume flow in litres per hour 10 | t_hc;T-HC;The inflow temperature in the direct heating circuit is displayed in C. 11 | t_hc_set;T-HC Setpoint;The set temperature of the flow in the direct heating circuit is displayed in C. 12 | status_pump;Status HS Pump;The current status of the internal heat circulation pump in the ROTEX HPSU compact is displayed. 13 | runtime_comp;Runtime Compressor;The running time of the refrigerant compressor is displayed in h. 14 | runtime_pump;Runtime Pump;The running time of the internal heating circulation pump is displayed in h. 15 | posmix;Mixer Position;The current position of the 3UV DHW 3-way switch valve is displayed. 0%: position A (room heating) 100%: position B (domestic hot water generation) 16 | qboh;Qboh;The amount of heat in the additional heat generator for hot water generation is displayed in kWh. 17 | qchhp;Qchhp;The amount of heat in the additional heat generator for heating mode is displayed in kWh. 18 | qsc;Qsc;The quantity of heat in the heat pump for cooling is displayed in kWh. 19 | qch;Qch;The quantity of heat in the heat pump for heating is displayed in kWh. 20 | qwp;QWP;The total amount of heat in the heat pump is displayed in kWh. 21 | qdhw;Qdhw;The quantity of heat for hot water generation is displayed in kWh. 22 | sw_vers_01;Version SW 1;Version SW 1 23 | sw_vers_02;Version SW 2;Version SW 2 24 | sw_vers_03;Version SW 3;Version SW 3 25 | mode_01;Operating mode; Parameter for setting the operating mode of the internal heating circuit. For the setting "- - - -" for this heating circuit the rotary switch of the setting is used. By setting the operating mode "Standby / OFF" and "Summer" of the rotary switch of the control unit, the power reduction of all the heating or consumption circuits of the whole system is obtained. 0: --- 1: Standby 2: Reduce 3: Heating 4: Cooling 5: Summer 11: Automatic 1 12: Automatic 2 26 | tvbh2;TVBH2 [C];Current heating inflow temperature or temp. after heating support heat exchanger (tV,BH). 27 | tliq2;Tliq2 [C];Current coolant temperature (tliq2). 28 | tr2;TR2 [C];Current heating return flow temperature, secondary sensor (tR2). 29 | ta2;TA2 [C];Actual outdoor temperature (measured by temperature sensor of the external heat pump) 30 | tdhw2;Tdhw2 [C];Current temperature in domestic hot water storage tank, secondary sensor (tDHW2). 31 | quiet;quiet;Shows the status of the whisper mode. 32 | mode;Mode;Current mode of the heat pump: ---: No heating or cooling demand : Heating : Cooling : Domestic hot water generation : Automatic defrosting function active 33 | pump;Pump;Actual output of the internal heating circulation pump in % 34 | ext;Ext;Current energy mode of the heat pump: LT: EVU function HT/NT active and low tariff. HT: EVU function HT/NT active and high tariff. SGN: EVU function SMART GRID active, normal mode. SG1: EVU function SMART GRID active, disconnection: no heat pump operation, no frost protection function. SG2: EVU function SMART GRID active, switchon recommendation, mode with higher set temperatures, cheap power. SG3: EVU function SMART GRID active, switchon command and storage tank charging to 70 C, cheap power - - -: No external mode active, heat pump works in normal mode. 35 | ehs;EHS;Current output of the backup heater in kW 36 | rt;RT;Parameter [Room thermostat] / [Interlink fct] 37 | bpv;BPV;Current position of the mixing valve 3UVB1 (100% = A, 0% = B) 38 | t_v1;TV;Current inflow temperature after the plate heat exchanger (tV1) 39 | t_dhw1;Tdhw;Current temperature in domestic hot water storage tank (tDHW1) 40 | t_vbh;TVBH;Current heating inflow temperature or temp. after heating support heat exchanger (tV,BH) 41 | t_outdoor_ot1;TA;Actual outdoor temperature (measured by optional temperature sensor RoCon OT1) 42 | t_r1;TR;Current heating return flow temperature (tR1) 43 | v1;V;Actual volume flow (flow rate) in the heating system 44 | t_room1_setpoint;T Room 1 Setpoint; Setpoint 1 value 45 | t_room2_setpoint;T Room 2 Setpoint; Setpoint 1 value 46 | t_room3_setpoint;T Room 3 Setpoint; Setpoint 1 value 47 | heat_slope;Heat-Slope; Heat Slope 48 | t_dhw_setpoint1;T-ACS nom 1;Nominal value of the hot water temperature in C, which is valid for the first ignition cycle 49 | t_dhw_setpoint2;T-ACS nom 2;Nominal value of the hot water temperature in C, which is valid for the second ignition cycle 50 | t_dhw_setpoint3;T-ACS nom 3;Nominal value of the hot water temperature in C, which is valid for the third ignition cycle 51 | hyst_hp;Hyst HP;Switching threshold hot water charging. Setting of the temperature difference to which the temperature in the domestic hot water storage tank compared to the current target hot water temperature [T-DHW Setpoint] can drop before the heat pump is switched on to provide hot water 52 | t_flow_cooling;T-Flow Cooling;Setting the cooling inflow target temperature (fixed value) when cooling mode is active 53 | error;error;errorcode 54 | outdoor_type;Outdoor type;Type exterior heat pump unit 55 | indoor_unit;Indoor unit;Type of interior heat pump unit 56 | func_heating;Function Heating;Setting as to whether there is an additional heat generator (WEZ) for hot water generation and heating support 57 | hzu;HUZ;Heating support from domestic hot water storage tanks when the minimum temperature is exceeded 58 | equi_func;Equilibrium Function;The bivalence function is relevant for operation of the optional ancillary heater based on a backup demand (room heating operation) 59 | smart_grid;SMART GRID;Smart Grid 60 | modus_sg;Mode SG;Only if parameter [SMART GRID] = 1:Used for a possible target temperature increase in the case of aSMART GRID start command 61 | ht_nt_func;HT/NT Function;Setting which specifies which heat sources are switched off when the standard signal is received from the energy supply company (EVU) in the case of the customer having an off-peak tariff network connection 62 | ht_nt_contact;HT/NT Contact;Specifies whether the HT/NT input is an NC or NO contact 63 | room_therm;Room thermostat;Configuration of a room thermostat connected to the port J16 on the ROTEX HPSU compact using potential-free contacts 64 | interlink;Interlink fct;Configuration for systems operating with 2 different inflow target temperatures 65 | air_purge;Air Purge;Activation of automatic bleeding of the ROTEX HPSU compact and the connected heating circuit 66 | max_perf_pump;Max Perform Pump;Upper limit for modulation of the pump output 67 | min_perf_pump;Min Perform Pump;Lower limit for modulation of the pump output 68 | outside_conf;Outside Config;Configuration of the optional external temperature sensor RoCon OT1 69 | storage_conf;Storage Config;Configuration of water heating 70 | pres_conf;Pressure Config;Configuring the sensor for assessment of the system water pressure 71 | out_temp_adapt;Outside Temp Adap;Individual adapting for the measured value of the outdoor temperature relevant for the Controller 72 | power_dhw;Power DHW;Heating output of electric auxiliary heater for hot water generation 73 | buh_s1_pow;BUH s1 power;Heat capacity of the ancillary electric heater in Stage 1 heating support 74 | buh_s2_pow;BUH s2 power;Heat capacity of the ancillary electric heater in Stage 2 heating support 75 | power_biv;Power BIV;Setting limits the output of the heating support 76 | tdiff_dhw_ch;TDiff-DHW CH;TDiff-DHW CH 77 | t_vbh1_max;T vbh1 max;Setting limits the inflow temperature (measured at tV, BH) with active heating support function 78 | equi_temp;Equilibrium Temp;Setting affects the operation of the potential-free AUX switching contact (toggle switch utput A) defined in the parameter [AUX Fct] 79 | quiet_mode;Quiet Mode;Mode for low-noise operation with reduced output 80 | aux_fct;AUX Fct;Setting assigns the switching conditions to the potential-free AUX contact (toggle switch output A) 81 | aux_time;AUX time;AUX switching contact (A) switches with a delay when the switching condition is pending for longer than the set time 82 | t_dhw_1_min;T-DHW 1 min;Switching threshold storage tank temperature (Tdhw) for AUX switching contact (see parameter [AUX Fct]) 83 | delta_t_ch;Delta-T CH;Set outdoor temperature spread The ROTEX HPSU compact heating circulation pump controls the flow rate in order to achieve the set spread between the inflow target temperature and the return flow temperature (tV, BH – tR1) 84 | v_var;V var;Current minimum necessary volume flow in the system (calculated value, not configurable) 85 | t_flow_ch_adj;T-Flow CH adj;Only when parameter [Interlink fct] = On. With a closed cooling RT switching contact, the inflow target temperature is increased by the set value 86 | t_flow_cool_adj;T-Flow Cooling adj;Only when parameter [Interlink fct] = On. With a closed cooling RT switching contact, the cooling inflow target temperature is reduced by the set value 87 | min_pressure;Min Pressure;Defines the minimum water pressure 88 | max_pressure;Max Pressure;Defines the maximum water pressure 89 | setpoint_pressure;Set Point Pressure;Defines the set water pressure 90 | max_pressure_drop;Max Pressuredrop;Defines the maximum acceptable pressure drop in the heating system 91 | hc_func;HC Function;Setting defines the type of inflow temperature control 92 | t_frost_protect;T-Frost Protect;0=No frost protection of the heating circuit, Otherwise: If the outside temperature falls below the programmed value, the system switches into the frost protection mode (switches the pumps on). The function ceases once the outside temperature has risen to the set value +1 K 93 | insulation;Insulation;Setting the insulation standard of the building. This affects the way the heating curve and the heating times automatically adapt to the outside temperature. 94 | screed;Screed;Function for screed drying 95 | screed_day1;Temp screed day 1;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 96 | screed_day2;Temp screed day 2;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 97 | screed_day3;Temp screed day 3;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 98 | screed_day4;Temp screed day 4;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 99 | screed_day5;Temp screed day 5;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 100 | screed_day6;Temp screed day 6;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 101 | screed_day7;Temp screed day 7;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 102 | screed_day8;Temp screed day 8;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 103 | screed_day9;Temp screed day 9;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 104 | screed_day10;Temp screed day 10;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 105 | screed_day11;Temp screed day 11;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 106 | screed_day12;Temp screed day 12;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 107 | screed_day13;Temp screed day 13;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 108 | screed_day14;Temp screed day 14;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 109 | screed_day15;Temp screed day 15;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 110 | screed_day16;Temp screed day 16;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 111 | screed_day17;Temp screed day 17;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 112 | screed_day18;Temp screed day 18;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 113 | screed_day19;Temp screed day 19;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 114 | screed_day20;Temp screed day 20;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 115 | screed_day21;Temp screed day 21;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 116 | screed_day22;Temp screed day 22;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 117 | screed_day23;Temp screed day 23;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 118 | screed_day24;Temp screed day 24;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 119 | screed_day25;Temp screed day 25;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 120 | screed_day26;Temp screed day 26;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 121 | screed_day27;Temp screed day 27;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 122 | screed_day28;Temp screed day 28;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 123 | t_out_lim_day;T-Outside lim day;Setting the procedural program for screed heating. An individual inflow temperature can be set for each day for a maximum period of 28 days. The end of the screed programme is defined by the 1st. Day at target value setting 124 | t_out_lim_night;T-Outside lim night;"Parameter for setting the heating limit for ""Switch-off"" of the heating circuit during economy mode" 125 | t_flow_day;T-Flow Day;"Setting the inflow target temperature for the heating circuit during the heating time when in operating mode: ""Automatic 1"", ""Automatic 2"", ""Heating""" 126 | t_flow_night;T-Flow night;" Setting the inflow target temperature for the heating circuit during the setback time when in operating mode: ""Automatic 1"", ""Automatic 2"", ""Reducing""" 127 | max_t_flow;Max T-Flow;The inflow temperature determined for the heating circuit is limited to the maximum value set here 128 | min_t_flow;Min T-Flow;The inflow temperature determined for the heating circuit is limited to the minimum value set here 129 | hc_adapt;HC Adaption;HC Adapation 130 | start_tout_cool;Start T-Out Cooling;Setting from which outside temperature the cooling operation with the highest cooling infeed target temperature 131 | max_tout_cool;Max T-Out Cooling;Setting to determine from which outdoor temperature the lowest cooling flow temperature 132 | t_flow_cool_start;T-Flow Cooling start;Setting the cooling inflow target temperature at the start of cooling mode 133 | t_flow_cool_max;T-Flow Cooling max;Setting the minimum cooling inflow target temperature. This is kept constant relative to the outside temperature 134 | min_t_flow_cool;Min T-Flow Cooling;Setting the absolute lower limit of the cooling inflow target temperature. The limitation is effective if a lower cooling inflow target temperature is determined based on other parameter settings 135 | t_flow_cool;T-Flow Cooling;Setting the cooling inflow target temperature (fixed value) when cooling mode is active 136 | cool_setpoint_adj;Cooling Setpoint adj;Parallel displacement of the cooling characteristic curve to match the set value 137 | circ_pump_dhw;Circl-Pump DHW;Setting for activating a circulation pump 138 | circ_pump_interval;Circl-Pump Interval;Setting the interval control for an optional circulation pump 139 | anti_leg_day;Anti-Legionella day;Setting the day for the thermal disinfection of the circulating tank 140 | anti_leg_time;Anti-Legionella time;Setting the start time of the thermal disinfection of the hot water circulating tank 141 | anti_leg_temp;Anti-Legionella temp;Setting the hot water target temperature during thermal disinfection of the hot water circulating tank 142 | max_dhw_loading;Max DHW loading;Setting limits the time period for hot water generation to the set target value 143 | dhw_off_time;DHW Off Time;Setting the block time following completion or interruption of a hot water generation cycle. New demand of hot water generation is satisfied only after expiry of this block time 144 | one_hot_water;1x Hot Water;Start of the one-off heating up of the hot water and the set value [T-DHW Setpoint 1], independent of the heating programmes 145 | timer_boh;Timer BOH;Delay time after which the reserve heating may support the heat pump in hot water charging 146 | t_reduced;T-Reduced;Target room temperature for the setback times for the permanent timer programmes [Automatic 1] and [Automatic 2] 147 | t_absence;T-Absence;Target room temperature for the setback times for the temporary timer programmes [Away] and [Vacation] 148 | t_room;T-Room;Room temperature measured by an optional Rocon U1 room station 149 | -------------------------------------------------------------------------------- /etc/pyHPSU/commands_hpsu_IT.csv: -------------------------------------------------------------------------------- 1 | name;label;description 2 | t_hs;T-GDC;Viene visualizzata la temperatura corrente (di mandata) del generatore di calore. 3 | t_hs_set;T-GDC nom;Viene visualizzata la temperatura nominale corrente del generatore di calore in °C con un valore decimale. 4 | water_pressure;Pressione Acqua;Viene visualizzata la pressione idrica corrente espressa in bar. 5 | t_ext;T-Esterna;Viene visualizzata la temperatura esterna corrente in °C con un valore decimale. 6 | t_dhw;T-Ac;Viene visualizzata la temperatura corrente del bollitore di acqua calda in°C con un valore decimale. Se non fosse attivata alcuna funzione acqua calda, viene visualizzato "- - -". 7 | t_dhw_set;T-Accumulatore; Viene visualizzata la temperatura nominale corrente per l'approntamento di acqua calda in °C con un valore decimale. Se non fosse attivata alcuna funzione acqua calda, viene visualizzato "- - -". Il valore nominale corrente qui è sempre il valore massimo di tutte le richieste rilevanti per questo circuito dell'acqua calda. 8 | t_return;T-ritorno; Viene visualizzata la temperatura di ritorno corrente del generatore di calore in °C con un valore decimale. Se non è collegato il relativo sensore al generatore di calore, viene visualizzato "- - -" 9 | flow_rate;Flusso volumetrico;Viene visualizzato il valore filtrato del flusso di volume corrente. 10 | t_hc;Temp. Circ. Riscald;Viene visualizzata la temperatura del circuito di riscaldamento diretto in °C con un valore decimale. 11 | t_hc_set;Temp. Nomin. Circ. Risc.;Viene visualizzata la temperatura nominale (di mandata) del circuito di riscaldamento diretto in °C con un valore decimale. 12 | status_pump;Status pompa;Stato attuale della pompa di circolazione per riscaldamento interna del ROTEX HPSU compact. 13 | runtime_comp;Tempo oper. Comp;Viene visualizzato il tempo di funzionamento del compressore espresso in ore. 14 | runtime_pump;Tempo oper. Pompa;Viene visualizzato il tempo di funzionamento della pompa. 15 | posmix;Posizione Miscelatore;Viene visualizzata la posizione corrente del miscelatore 3UV1 in %. 16 | qboh;Qboh;Viene visualizzata la quantità di calore del riscaldamento di riserva per l'approntamento di acqua calda in kWh. 17 | qchhp;Qchhp;Viene visualizzata la quantità di calore del riscaldamento di riserva per la modalità di riscaldamento in kWh. 18 | qsc;Qsc;Viene visualizzata la quantità di calore della pompa di calore per la modalità di raffrescamento in kWh. 19 | qch;Qch;Viene visualizzata la quantità di calore della pompa di calore per la modalità di riscaldamento in kWh. 20 | qwp;QWP;Viene visualizzata l'intera quantità di calore della pompa di calore in kWh. 21 | qdhw;Qdhw;Viene visualizzata la quantità di calore per l'approntamento di acqua calda in kWh. 22 | sw_vers_01;Numero Software CUI;Viene visualizzato il software e la versione dell'unità di comando. 23 | sw_vers_02;Num Software Regolat;Viene visualizzato il numero di software e la versione della scheda di regolazione. 24 | sw_vers_03;SW Nr. RTX RT;Viene visualizzato il numero di software e la versione della scheda modbus. 25 | mode_01;Modo operativo;Parametro per l'impostazione della modalità di funzionamento del circuito di riscaldamento interno. Per l'impostazione "- - - -" per questo circuito di riscaldamento si utilizza l'interruttore rotante della regolazione. Con l'impostazione della modalità di funzionamento "Standby/OFF", e "Estate" dell'interruttore rotante della centralina, si ottiene la riduzione di potenza di tutti i circuiti di riscaldamento o di consumo di tutto l'impianto. 0: --- 1: Standby 2: Riduzione 3: Riscaldamento 4: Raffrescamento 5: Estate 11: Automatico 1 12: Automatico 2 26 | tvbh2;TVBH2 [C];Temperatura di mandata attuale riscaldamento (tV,BH). 27 | tliq2;Tliq2 [C];Temperatura corrente del refrigerante (tliq2). 28 | tr2;TR2 [C];Temperatura di ritorno attuale riscaldamento, sensore secondario (tR2). 29 | ta2;TA2 [C];Temperatura esterna attuale (misurata dalla sonda della pompa di calore esterna). 30 | tdhw2;Tdhw2 [C];Temperatura dell'acqua calda attuale nel bollitore dell'acqua calda, sensore secondario (tDHW2). 31 | quiet;Modalità silenziosa;Modalità per funzionamento silenzioso Esistono due modalità. In determinati casi, il funzionamento silenzioso si nota a causa della riduzione della potenza. 0: disattivato 1: attivato 2: Intervallo (funzionamento notturno fra le ore 22:00 e le ore 5:00 in modalità silenziosa) 32 | mode;Mode;Modalita' attuale della pompa di calore: 0: not active 1: riscaldare 2: Raffreddare 3: Funzione scongelamento attiva (Defrost) 4: Produzione di acqua calda (ACS) 33 | pump;Pump;Potenza attuale della pompa di circolazione per riscaldamento interna in %. 34 | ext;Ext;Modalita' energetica attuale della pompa di calore:\nLT: Funzione EVU attiva e tariffa ridotta.\nHT: Funzione EVU attiva e tariffa normale.\nSGN: SMART GRID - Funzione attiva, funzionamento\nnormale.\nSG1: SMART GRID - Funzione attiva, lancio,\ncorrente piu' cara.\nSG2: SMART GRID - Funzione attiva, funzionamento\naumentato, corrente piu' conveniente.\nSG3: SMART GRID - Funzione attiva, comando di attivazione e funzionamento aumentato, corrente piu' conveniente. '- - -': Nessuna modalita' esterna attiva, la pompa di calore funziona in modo normale. 35 | ehs;EHS;Potenza attuale del Backup-Heater (BUH) in kW. 36 | rt;Room thermostat;Attivazione di un termostato ambientale. Attivando questa funzione, la temperatura nominale ambientale viene controllata solo tramite il termostato ambientale. 0: Disattivato 1: Attivato 37 | bpv;BPV;Posizione attuale della valvola di miscelazione 3UVB1 (100 % = A, 0 % = B). 38 | t_v1;TV;Temperatura di mandata corrente (tV1). 39 | t_dhw1;Tdhw;Temperatura dell'acqua calda attuale nel bollitore dell'acqua calda (tDHW1). 40 | t_vbh;TVBH;Temperatura di uscita dell'acqua bollitore dell'acqua calda (tV,BH). 41 | t_outdoor_ot1;TA;Temperatura esterna attuale (misurata dalla sonda di temperatura opzionale RoCon OT1). 42 | t_r1;TR;Temperatura di ritorno attuale riscaldamento (tR1). 43 | v1;V;Flusso di volume attuale (portata) nell'impianto di riscaldamento. 44 | t_room1_setpoint;T-Ambiente 1;Viene impostato il valore nominale della temperatura ambiente in °C con un valore decimale, che vale per il primo blocco di programma a orario del programma a orario Automatico 1 e Automatico 2. (testo dal manuale installatore) Questi parametri influenzano, oltre alla temperatura esterna, la curva calore e possibilmente la temperatura ambiente rilevata dal dispositivo di controllo EHS157034 (se presente e configurato), la temperatura di mandata desiderata per il circuito di riscaldamento. Se questi parametri vengono impostati erroneamente, questo può influenzare fortemente il funzionamento della pompa calore in modalità riscaldamento. 45 | t_room2_setpoint;T-Ambiente 2;Viene impostato il valore nominale della temperatura ambiente in °C con un valore decimale, che vale per il primo blocco di programma a orario del programma a orario Automatico 1 e Automatico 2. (testo dal manuale installatore) Questi parametri influenzano, oltre alla temperatura esterna, la curva calore e possibilmente la temperatura ambiente rilevata dal dispositivo di controllo EHS157034 (se presente e configurato), la temperatura di mandata desiderata per il circuito di riscaldamento. Se questi parametri vengono impostati erroneamente, questo può influenzare fortemente il funzionamento della pompa calore in modalità riscaldamento. 46 | t_room3_setpoint;T-Ambiente 3;Viene impostato il valore nominale della temperatura ambiente in °C con un valore decimale, che vale per il primo blocco di programma a orario del programma a orario Automatico 1 e Automatico 2. (testo dal manuale installatore) Questi parametri influenzano, oltre alla temperatura esterna, la curva calore e possibilmente la temperatura ambiente rilevata dal dispositivo di controllo EHS157034 (se presente e configurato), la temperatura di mandata desiderata per il circuito di riscaldamento. Se questi parametri vengono impostati erroneamente, questo può influenzare fortemente il funzionamento della pompa calore in modalità riscaldamento. 47 | heat_slope;Curva riscaldamento;La curva di riscaldamento riproduce la dipendenza della temperatura nominale di mandata des circuito di riscaldamento dalla temperatura esterna. 48 | t_dhw_setpoint1;T-Acc 1 nom; Viene impostato il valore nominale della temperatura dell'acqua calda in °C con un valore decimale, che vale per il primo blocco di programma a orario del programma a orario Automatico 1 e Automatico 2. (testo dal manuale installatore) Valore desiderato della temperatura dell'acqua calda. All'avvio non impostare al di sotto di 40°C. Dopo l'avvio non impostare mai al di sotto di 35°C! 49 | t_dhw_setpoint2;T-Acc 2 nom;Viene impostato il valore nominale della temperatura dell'acqua calda in °C con un valore decimale, che vale per il secondo blocco di programma a orario del programma a orario Automatico 1 e Automatico 2. 50 | t_dhw_setpoint3;T-Acc 3 nom;Viene impostato il valore nominale della temperatura dell'acqua calda in °C con un valore decimale, che vale per il terzo blocco di programma a orario del programma a orario Automatico 1 e Automatico 2. 51 | hyst_hp;HP Isteresi TDHW;Soglia di attivazione caricamento acqua calda. Stabilisce a partire da quale differenza di temperatura si attiva la pompa di calore per il caricamento dell'acqua calda 52 | t_flow_cooling;T-Imp refrig;Temperatura nominale di mandata di modalita' di raffreddamento in caso di regolazione in base ad una temperatura di mandata fissa 53 | error;Errore;errorcode 54 | outdoor_type;Outdoor type;Tipo di apparecchio esterno pompa di calore 0: nessuna selezione 1: 4 kW 2: 6 kW 3: 8 kW 4: 11 kW 5: 14 kW 6: 16 kW 55 | indoor_unit;Indoor unit;Tipo apparecchio interno pompa di calore 0: Finora non si verifica alcuna messa in funzione. 1: 304 2: 308 3: 508 4: 516 56 | func_heating;Function Heating Rod;Impostazione relativa all'eventuale presenza di generatore di calore aggiuntivo (WEZ) per l'approntamento di acqua calda e il sostegno al riscaldamento. 0: Nessun WEZ aggiuntivo 1: WEZ elettrico 2: WEZ alternativo per le funzioni approntamento di acqua calda e sostegno al riscaldamento 3: WEZ 1 alternativo per la funzione approntamento di acqua calda e WEZ 2 alternativo per la funzione sostegno al riscaldamento (testo manuale installatore) Durante l'utilizzo di un l’elemento riscaldante elettronico supportare la pompa di calore, impostare su 1. 57 | hzu;HUZ;Sostegno al riscaldamento tramite il bollitore di acqua calda : 0: nessun sostegno al riscaldamento 1: sostegno al riscaldamento attivato 58 | equi_func;Equilibrium Func;(o Bivalence Function) La temperatura bivalente è rilevante per il funzionamento del riscaldatore aggiuntivo opzionale a seguito di una richiesta di back-up [modalità di riscaldamento ambientale]. Quando la funzione è attivata, il back-up heater viene sbloccato solo se la temperatura bivalente (impostabile alla voce Configurazione) non è stata raggiunta. Disattivando la funzione "Temperatura bivalente", il funzionamento del back-up heater è sempre possibile. 0: Disattivato 1: attivato (testo nel manuale tecnico) Quando attivato, l'elemento riscaldante elettronico per il supporto del riscaldamento verrà attivato per la prima volta quando la temperatura è al di sotto dei valori impostati in„Temp. di bivalenza“. 59 | smart_grid;SMART GRID;Attivazione della funzione Smart Grid Non appena viene attivata questa funzione, a seconda del segnale inviato dal fornitore di energia elettrica, la pompa di calore viene disattivata o azionata maggiormente. 0: Disattivato 1: attivato 60 | modus_sg;Mode SG;Attivando il parametro "SMART GRID" (=1), tramite di esso si può regolare la riduzione di temperatura in modalità di risparmio (approntamento di acqua calda e riscaldamento) e l'aumento della temperatura di mandata con un comando di attivazione. 0: Comfort (aumento del valore nominale della temperatura dell'acqua calda di 5 K) 1: Standard (aumento del valore nominale della temperatura di mandata di 2 K e temperatura dell'acqua calda di 5 K) 2: Eco (aumento del valore nominale della temperatura di mandata di 5 K e temperatura dell'acqua calda di 10 K) 61 | ht_nt_func;HT/NT Function;Questo parametro stabilisce quali sorgenti di calore vengono disattivate quando si riceve il segnale della tariffa ridotta dall'ente di approvvigionamento energetico (EVU). 0: Disattivato (nessun effetto) 1: Compressore disattivato 2: Il compressore e il riscaldamento di riserva viene disattivato 3: Tutto viene disattivato (nessuna funzione dell'apparecchio, stand-by) 62 | ht_nt_contact;HT/NT Contact;Determinare se si tratti di un contatto di apertura o chiusura (NC or NO). 0: Valutazione di un contatto di chiusura 1: Valutazione di un contatto di apertura 63 | room_therm;Room thermostat;Attivazione di un termostato ambientale. Attivando questa funzione, la temperatura nominale ambientale viene controllata solo tramite il termostato ambientale. 0: Disattivato 1: Attivato 64 | interlink;Interlink fct;È possibile utilizzarlo solo negli impianti dotati di sonde di valore nominale diverse (ad es. 2º termostato ambientale). Questa impostazione di parametro offre la possibilità di utilizzare 2 valori nominali. Non appena viene attivata questa funzione (ad es. connettendo un ulteriore convettore HP), a seconda della richiesta, la regolazione avviene in base a 2 valori nominali. Il secondo valore nominale corrisponde al normale valore nominale +5 K (in caso di raffrescamento -5 K). 0: Disattivato 1: Attivato (testo dal manuale installatore) La temperatura di mandata viene modificata quando il secondo contatto del RT (contatto raffreddamento, Connettore J16) è chiuso al valore impostato nel parametro “T-Flow CH adj“ o „T-Flow Cooling adj“ ( RoCon HP, Cap. 6.2.2, Tab. 6-2). 65 | air_purge;Air Purge;Activation of automatic bleeding of the ROTEX HPSU compact and the connected heating circuit 66 | max_perf_pump;PWM MAX;Limite superiore della modulazione del segnale PWM. (testo del manuale installatore) Max Performance - Definisce l'energia massima prodotta dalla pompa 67 | min_perf_pump;PWM MIN;Limite inferiore della modulazione del segnale PWM. (testo del manuale installatore) Min Performance - Definisce la potenza minima dalla pompa 68 | outside_conf;Outside Config;Parametro per la configurazione del sensore di temperatura esterna. Se il parametro è attivato e non è stato collegato alcun sensore esterno, viene generato un messaggio di errore. 0: Disattivato 1: Attivato 69 | storage_conf;Storage Config;Con questo parametro, è possibile parametrare il sensore dell'approntamento di acqua calda. Nell'impostazione 0: "Inattivo" non viene valutato alcun sensore e la funzionalità dell'approntamento di acqua calda è disattivata. Nell'impostazione 1: "Sensore" viene valutato un sensore e la funzionalità dell'approntamento di acqua calda è attivata. Nell'impostazione 2: "Termostato", per l'approntamento di acqua calda viene valutato un interruttore del termostato (ON /OFF), in cui il "contatto aperto" viene valutato come "nessuna necessità". La funzionalità dell'approntamento di acqua calda viene attivata. 0: Inattivo 1: Sensore 2: Termostato 70 | pres_conf;Pressure Config; Parametro per la configurazione del sensore per la registrazione della pressione dell'acqua Impianto. 0: Disattivato 1: Attivato 71 | out_temp_adapt;Outside Temp Adap;Con questo parametro si può impostare un adeguamento personalizzato per il valore di misurazione della temperatura esterna rilevante per la regolazione. 72 | power_dhw;BOH power;Potenza calorifica del riscaldatore elettrico aggiuntivo per l'approntamento di acqua calda 73 | buh_s1_pow;BUH s1 power;Potenza calorifica del riscaldatore elettrico aggiuntivo per il sostegno al riscaldamento livello 1 (in W) (testo dal manuale installatore) Definisce l'energia prodotta dall'elemento elettronico riscaldante installato, collegato al rispettivo stadio, e limita l'energia che viene utilizzata come supporto al riscaldamento del serbatoio attraverso la valvola miscelatrice. Se durante il supporto al riscaldamento attraverso l'elemento riscaldante elettronico il serbatoio diventa troppo caldo o si raffredda eccessivamente, si può verificare una deriva del sensore. Questo può essere contrastato modificando il valore del parametro come da Tab.3-4. 74 | buh_s2_pow;BUH s2 power;Potenza calorifica del riscaldatore elettrico aggiuntivo per il sostegno al riscaldamento livello 2 (in W) (testo dal manuale installatore) Definisce l'energia prodotta dall'elemento elettronico riscaldante installato, collegato al rispettivo stadio, e limita l'energia che viene utilizzata come supporto al riscaldamento del serbatoio attraverso la valvola miscelatrice. Se durante il supporto al riscaldamento attraverso l'elemento riscaldante elettronico il serbatoio diventa troppo caldo o si raffredda eccessivamente, si può verificare una deriva del sensore. Questo può essere contrastato modificando il valore del parametro come da Tab.3-4. 75 | power_biv;Power BIV;Potenza calorifica del generatore di calore alternativo. Serve alla limitazione del sostegno al riscaldamento. La potenza viene azionata con il sostegno al riscaldamento fino a quando non si raggiunge il parametro limite di temperatura [Overtemp CH Support]. 76 | tdiff_dhw_ch;TDiff-DHW CH;TDiff-DHW CH 77 | t_vbh1_max;T vbh1 max;Massima temperatura di mandata (controllata tramite la valvola di miscelazione integrata). Limita il sostegno al riscaldamento alla temperatura immessa. (alternativo) Temperatura di erogazione massima dell'acqua (misurata su tV, BH) con funzione "heating support" attiva 78 | equi_temp;Temp. di bivalenza; Temperatura esterna a partire dalla quale viene attivato il riscaldatore aggiuntivo opzionale per il sostegno al riscaldamento ambientale. La temperatura bivalente è rilevante per il funzionamento del riscaldatore aggiuntivo opzionale a seguito di una richiesta di back-up [modalità di riscaldamento ambientale]. A tale scopo viene utilizzato il sensore di temperatura integrato sull'apparecchio esterno della pompa di calore (si differenzia da quelli indicato nel display). 79 | quiet_mode;Quiet Mode;Modalità per operatività silenziosa con output ridotto 80 | aux_fct;AUX Fzn;Attribuzione delle condizioni di attivazione per il contatto AUX. 0: Funzione disattivata 1: TDHW 1 min 2: Modalità di funzionamento 3: BUH 4: Errore 5: TVBH1 save 6: BIV parallelo 7: BIV alternativo 8: BOH 81 | aux_time;AUX Tempo;Tempo di ritardo (isteresi) funzione speciale, dopo questo periodo viene attivato il contatto AUX. 82 | t_dhw_1_min;T-DHW min; Soglia di attivazione per contatto AUX dipendente dalla temperatura vedere RPS3 (BSK) / Soglia di commutazione della temperatura del serbatorio di accumulo (Tdhw) per il contatto di commutazione AUX (vedi parametro [AUX Fct]) 83 | delta_t_ch;Spread CH;(Delta-T CH) Differenza di temperatura soglia superiore dimodulazione per modalità di riscaldamento. (traduzione non disponibile) Set outdoor temperature spread The ROTEX HPSU compact heating circulation pump controls the flow rate in order to achieve the set spread between the inflow target temperature and the return flow temperature (tV, BH – tR1) 84 | v_var;V var;La portata d'aria minima necessaria dell'unità (valore aritmetico, non impostabile) 85 | t_flow_ch_adj;T-Flow CH adj;(traduzione non disponibile) Only when parameter [Interlink fct] = On. With a closed cooling RT switching contact, the inflow target temperature is increased by the set value 86 | t_flow_cool_adj;T-Flow Cooling adj;(traduzione non disponibile) Only when parameter [Interlink fct] = On. With a closed cooling RT switching contact, the cooling inflow target temperature is reduced by the set value 87 | min_pressure;Min Pressure;Indica la pressione minima dell'acqua 88 | max_pressure;Max Pressure;Indica la pressione massima dell'acqua 89 | setpoint_pressure;Set Point Pressure;Indica la pressione obiettivo dell'acqua 90 | max_pressure_drop;Max Pressuredrop;Indica il massimo calo di pressione accettabile nel sistema di riscaldamento 91 | hc_func;HC Function;Al circuito di riscaldamento si possono attribuire varie funzionalità. 0: Regolazione circuito di riscaldamento standard (curva climatica) 1: Regolazione a un valore nominale di mandata fisso, a seconda della modalità di riscaldamento o riduzione 92 | t_frost_protect;Antigelo;0=Nessuna protezione del circuito di riscaldamento, Altrimenti: Se la temperatura esterna scende al di sotto del valore programmato, l'impianto passa alla modalità di protezione dal congelamento (accensione della pompa). La funzionalità si disattiva una volta che la temperatura esterna ha raggiunto il valore impostato +1 K 93 | insulation;Livello Isolamento;Con questo parametro, è possibile parametrare lo standard di coibentazione dell'edificio. IN tal modo si influenza la curva di riscaldamento e i tempi di riscaldamento e raffrescamento. 0: off 1: scarso 2: normale 3: buono 4: ottimo (testo del manuale installatore) A seconda dell'isolamento dell'edificio, la media della temperatura esterna viene calcolata su un dato periodo di tempo. Perciò può succedere che la pompa di calore non si accenda immediatamente quando la temperatura esterna raggiunge un valore inferiore a quello impostato in „Temp.-Lim Giorno“ . La temperatura esterna media può essere visualizzata nel livello Informazioni sotto la voce „T-Esterna“ 94 | screed;Massetto;Con questo parametro si può attivare la funzione di asciugatura del massetto. La temperatura nominale di mandata viene regolata in base al programma massetto parametrato. Il giorno in cui viene attivata la funzione massetto non viene conteggiato nella durata del programma massetto. Il primo giorno comincia quindi al volgere del giorno ovvero alle ore 00:00. Per le restanti ore del giorno di attivazione, il riscaldamento segue l'impostazione del primo giorno di programma. 95 | screed_day1;Temp programma massetto giorno 1;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 96 | screed_day2;Temp programma massetto giorno 2;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 97 | screed_day3;Temp programma massetto giorno 3;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 98 | screed_day4;Temp programma massetto giorno 4;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 99 | screed_day5;Temp programma massetto giorno 5;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 100 | screed_day6;Temp programma massetto giorno 6;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 101 | screed_day7;Temp programma massetto giorno 7;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 102 | screed_day8;Temp programma massetto giorno 8;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 103 | screed_day9;Temp programma massetto giorno 9;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 104 | screed_day10;Temp programma massetto giorno 10;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 105 | screed_day11;Temp programma massetto giorno 11;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 106 | screed_day12;Temp programma massetto giorno 12;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 107 | screed_day13;Temp programma massetto giorno 13;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 108 | screed_day14;Temp programma massetto giorno 14;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 109 | screed_day15;Temp programma massetto giorno 15;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 110 | screed_day16;Temp programma massetto giorno 16;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 111 | screed_day17;Temp programma massetto giorno 17;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 112 | screed_day18;Temp programma massetto giorno 18;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 113 | screed_day19;Temp programma massetto giorno 19;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 114 | screed_day20;Temp programma massetto giorno 20;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 115 | screed_day21;Temp programma massetto giorno 21;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 116 | screed_day22;Temp programma massetto giorno 22;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 117 | screed_day23;Temp programma massetto giorno 23;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 118 | screed_day24;Temp programma massetto giorno 24;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 119 | screed_day25;Temp programma massetto giorno 25;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 120 | screed_day26;Temp programma massetto giorno 26;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 121 | screed_day27;Temp programma massetto giorno 27;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 122 | screed_day28;Temp programma massetto giorno 28;In questa immissione si può parametrare il programma di svolgimento del riscaldamento del massetto. Si può impostare una temperatura nominale di mandata propria per una durata massima di 28 giorni separatamente per ogni giorno. La fine del programma massetto viene definita il primo giorno con l'impostazione del valore nominale "- - - -". 123 | t_out_lim_day;Temp.-Lim Giorno (esterna);Se la temperatura esterna media misurata tramite il regolatore supera la soglia di calore qui impostata di 1 K, il riscaldamento viene bloccato. Il riscaldamento viene sbloccato di nuovo quando la temperatura esterna scende al di sotto della soglia di calore impostata. 124 | t_out_lim_night;Temp.-Lim Notte (esterna);Parametro per l'impostazione del limite di riscaldamento per lo "Spegnimento" del circuito di riscaldamento durante il tempo di riduzione. 125 | t_flow_day;T-Flow Day;(traduzione non disponibile) Setting the inflow target temperature for the heating circuit during the heating time when in operating mode: "Automatic 1", "Automatic 2", "Heating" 126 | t_flow_night;T-Flow night;(traduzione non disponibile) Setting the inflow target temperature for the heating circuit during the setback time when in operating mode: "Automatic 1", "Automatic 2", "Reducing" 127 | max_t_flow;Max T-Flow;La temperatura nominale di mandata del circuito di riscaldamento viene limitata alla temperatura di mandata massima impostata (cioè non salirà sopra) 128 | min_t_flow;Min T-Flow;La temperatura nominale di mandata del circuito di riscaldamento viene aumentata alla temperatura di mandata minima impostata (cioè non scenderà sotto). 129 | hc_adapt;HC Adaption;Funzione per l'impostazione automatica della curva di riscaldamento 0: Disattivato 1: attivato 130 | start_tout_cool;T-esterna inizio Raffredd.;Con questo parametro si fissa a partire da quale temperatura esterna si avvia la modalità di raffrescamento (condizione di impostazione: modalità di raffrescamento). (non tradotto) Setting from which outside temperature the cooling operation with the highest cooling infeed target temperature 131 | max_tout_cool;T-esterna Rafr Max;Con questo parametro viene fissato con quale temperatura esterna viene fornita la temperatura nonimale di mandata di raffrescamento [T-madata inizio Rafredd.] più bassa o il valore nominale ambientale più alto [T-Room max cooling] (condizione di impostazione: modalità di raffrescamento). (non tradotto) Setting to determine from which outdoor temperature the lowest cooling flow temperature 132 | t_flow_cool_start;T-mandata inizio Rafredd.;(T-Flow Cooling start) Con questo parametro viene stabilito quale temperatura di mandata viene ottenuta all'inizio del raffrescamento (temperatura esterna = parametro [T-esterna inizio Raffredd.]) (condizione di impostazione: Parametro [raffrescare] = ON). (non tradotto) Setting the cooling inflow target temperature at the start of cooling mode 133 | t_flow_cool_max;T-mandata Rafredd. max;(T-Flow Cooling max) Con questo parametro viene stabilito quale temperatura di mandata viene ottenuta con massimo raffrescamento (temperatura esterna = parametro [T-mandata Rafredd. max]) (condizione di impostazione: modalità di raffrescamento). (non tradotto) Setting the minimum cooling inflow target temperature. This is kept constant relative to the outside temperature 134 | min_t_flow_cool;Min T-Flow Cooling;(traduzione non disponibile) Setting the absolute lower limit of the cooling inflow target temperature. The limitation is effective if a lower cooling inflow target temperature is determined based on other parameter settings 135 | t_flow_cool;T-Flow Cooling;(traduzione non disponibile) Setting the cooling inflow target temperature (fixed value) when cooling mode is active 136 | cool_setpoint_adj;Cooling Setpoint adj;Parallel displacement of the cooling characteristic curve to match the set value 137 | circ_pump_dhw;Pompa circ ACS;Con questo parametro si può impostare la funzione per il controllo di una pompa di circolazione in modo che essa venga sbloccata in sincronia al programma acqua calda. 0: Off 1: On 138 | circ_pump_interval;Intervallo pompa circ.;(traduzione non disponibile) Setting the interval control for an optional circulation pump 139 | anti_leg_day;Anti-Legionella giorno;Con questo parametro si può impostare la disinfezione termica del bollitore dell'acqua calda. 0 = Spento 1 = Lunedì ... 7 = Domenica 140 | anti_leg_time;Anti-Legionella tempo;Con questo parametro si può parametrare il tempo di avvio della disinfezione termica del serbatoio di acqua potabile. 141 | anti_leg_temp;Anti-Legionella temp;Con questo parametro si può parametrare la temperatura nominale della disinfezione termica del serbatoio di acqua potabile. 142 | max_dhw_loading;Max DHW loading;(traduzione non disponibile) Setting limits the time period for hot water generation to the set target value 143 | dhw_off_time;DHW Off Time;(traduzione non disponibile) Setting the block time following completion or interruption of a hot water generation cycle. New demand of hot water generation is satisfied only after expiry of this block time 144 | one_hot_water;1x acqua calda;Quando il valore desiderato [T-DHW Setpoint 1] viene raggiunto, questo parametro DEVE essere disattivato, diversamente, il serbatoio viene sempre mantenuto ad una temperatura di 37°C. Suggerimento: Disattivare sempre questo parametro (Impostazione 0)! 145 | timer_boh;Timer BOH;(traduzione non disponibile) Delay time after which the reserve heating may support the heat pump in hot water charging 146 | t_reduced;T-Riduzione;Viene impostato il valore nominale della temperatura ambientale di riduzione in °C con un valore decimale che vale per il programma a orario Automatico 1 e Automatico 2. 147 | t_absence;T-Asssenza;Viene impostato il valore nominale della temperatura ambientale di riduzione in °C con un valore decimale che vale per il programma a orario Assente e Vacanze 148 | t_room;T-Room;(traduzione non disponibile) Room temperature measured by an optional Rocon U1 room station 149 | -------------------------------------------------------------------------------- /etc/pyHPSU/pyhpsu.conf: -------------------------------------------------------------------------------- 1 | # settings for pyHPSUd 2 | [PYHPSUD] 3 | PYHPSUD_DEVICE=PYCAN 4 | PYHPSUD_LANG=EN 5 | PYHPSUD_PORT=/dev/ttyUSB0 6 | 7 | # settings for pyHPSU 8 | [PYHPSU] 9 | PYHPSU_DEVICE = PYCAN 10 | PYHPSU_PORT = /dev/ttyS0 11 | PYHPSU_LANG = DE 12 | OUTPUT_TYPE = JSON 13 | 14 | [CANPI] 15 | timeout=0.05 16 | 17 | [HOMEMATIC] 18 | # The token must be get in the CCU GUI 19 | TOKEN = XXXXXXXX 20 | HOST = 192.168.1.6 21 | 22 | # interval for each query for a value in seconds 23 | # values not listed here are not queried 24 | [JOBS] 25 | T_HS = 2 26 | T_HS_SET = 25 27 | water_pressure = 4 28 | t_ext = 6 29 | t_dhw = 25 30 | t_dhw_set = 60 31 | t_return = 4 32 | flow_rate = 2 33 | t_hc = 4 34 | t_hc_set = 2 35 | 36 | 37 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SHARE_DIR="/usr/share/pyHPSU/" 4 | CONF_DIR="/etc/pyHPSU" 5 | BIN_DIR="/usr/bin/" 6 | PACKAGE_DIR="/usr/share/doc/packages/pyHPSU" 7 | DIST_DIR="/usr/lib/python3/dist-packages/HPSU" 8 | SERVICE_DIR="/etc/systemd/system/" 9 | echo "Installing pyHPSU" 10 | if [ ! -d $CONF_DIR ]; then 11 | echo "Creating directory for config files" 12 | mkdir -p $CONF_DIR 13 | fi 14 | 15 | if [ ! -d $PACKAGE_DIR ]; then 16 | echo "Creating directory for shared files" 17 | mkdir -p $PACKAGE_DIR 18 | fi 19 | 20 | if [ ! -d $BIN_DIR ]; then 21 | echo "Creating directory for executable files" 22 | mkdir -p $BIN_DIR 23 | fi 24 | 25 | if [ ! -d $DIST_DIR ]; then 26 | echo "Creating directory for python includes files" 27 | mkdir -p $DIST_DIR 28 | fi 29 | if [ ! -d $SHARE_DIR ]; then 30 | echo "Creating directory for resource files" 31 | mkdir -p $SHARE_DIR 32 | fi 33 | 34 | # copy configs 35 | cp etc/pyHPSU/commands* $CONF_DIR/ 36 | if [ -f /etc/pyHPSU/pyhpsu.conf ]; then 37 | cp etc/pyHPSU/pyhpsu.conf $CONF_DIR/pyhpsu.conf.new 38 | else 39 | cp etc/pyHPSU/pyhpsu.conf $CONF_DIR/ 40 | fi 41 | 42 | # copy the rest 43 | cp -r resources/* $SHARE_DIR 44 | cp -r HPSU/* $DIST_DIR 45 | cp -r contrib $DIST_DIR 46 | 47 | # copy service file 48 | cp systemd/* $SERVICE_DIR 49 | systemctl --system daemon-reload 50 | 51 | # copy binarys 52 | cp pyHPSU.py $BIN_DIR 53 | cp pyHPSUd.py $BIN_DIR 54 | chmod a+x $BIN_DIR/pyHPSU.py 55 | chmod a+x $BIN_DIR/pyHPSUd.py 56 | 57 | echo "Installation done!!!" 58 | 59 | 60 | -------------------------------------------------------------------------------- /pyHPSU.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # -*- coding: utf-8 -*- 4 | 5 | 6 | import serial 7 | import sys 8 | #sys.path.append('/usr/share/pyHPSU/HPSU') 9 | #sys.path.append('/usr/share/pyHPSU/plugins') 10 | import os 11 | import getopt 12 | import time 13 | import locale 14 | import importlib 15 | import logging 16 | from HPSU.HPSU import HPSU 17 | import configparser 18 | import threading 19 | import csv 20 | import json 21 | 22 | SocketPort = 7060 23 | 24 | def main(argv): 25 | cmd = [] 26 | port = None 27 | driver = "PYCAN" 28 | verbose = "1" 29 | show_help = False 30 | output_type = "" 31 | upload = False 32 | lg_code = "EN" 33 | languages = ["EN", "IT", "DE"] 34 | logger = None 35 | pathCOMMANDS = "/etc/pyHPSU" 36 | global conf_file 37 | conf_file = None 38 | global default_conf_file 39 | default_conf_file = "/etc/pyHPSU/pyhpsu.conf" 40 | read_from_conf_file=False 41 | global auto 42 | global ticker 43 | ticker=0 44 | loop=True 45 | auto=False 46 | #commands = [] 47 | #listCommands = [] 48 | global config 49 | config = configparser.ConfigParser() 50 | global n_hpsu 51 | env_encoding=sys.stdout.encoding 52 | PLUGIN_PATH="/usr/lib/python3/dist-packages/HPSU/plugins" 53 | backup_mode=False 54 | global backup_file 55 | restore_mode=False 56 | global options_list 57 | options_list={} 58 | # 59 | # get all plugins 60 | # 61 | PLUGIN_LIST=["JSON", "CSV", "BACKUP"] 62 | PLUGIN_STRING="JSON, CSV, BACKUP" 63 | for file in os.listdir(PLUGIN_PATH): 64 | if file.endswith(".py") and not file.startswith("__"): 65 | PLUGIN=file.upper().split(".")[0] 66 | PLUGIN_STRING+=", " 67 | PLUGIN_STRING+=PLUGIN 68 | PLUGIN_LIST.append(PLUGIN) 69 | 70 | try: 71 | opts, args = getopt.getopt(argv,"ahc:p:d:v:o:l:g:f:b:r:", ["help", "cmd=", "port=", "driver=", "verbose=", "output_type=", "upload=", "language=", "log=", "config_file="]) 72 | except getopt.GetoptError: 73 | print('pyHPSU.py -d DRIVER -c COMMAND') 74 | print(' ') 75 | print(' -a --auto do atomatic queries') 76 | print(' -f --config Configfile, overrides given commandline arguments') 77 | print(' -d --driver driver name: [ELM327, PYCAN, EMU, HPSUD], Default: PYCAN') 78 | print(' -p --port port (eg COM or /dev/tty*, only for ELM327 driver)') 79 | print(' -o --output_type output type: [' + PLUGIN_STRING + '] default JSON') 80 | print(' -c --cmd command: [see commands domain]') 81 | print(' -v --verbose verbosity: [1, 2] default 1') 82 | print(' -l --language set the language to use [%s], default is \"EN\" ' % " ".join(languages)) 83 | print(' -b --backup backup configurable settings to file [filename]') 84 | print(' -r --restore restore HPSU settings from file [filename]') 85 | print(' -g --log set the log to file [_filename]') 86 | print(' -h --help show help') 87 | sys.exit(2) 88 | 89 | for opt, arg in opts: 90 | if opt in ("-a", "--auto"): 91 | auto = True 92 | options_list["auto"]="" 93 | 94 | if opt in ("-f", "--config"): 95 | read_from_conf_file = True 96 | conf_file = arg 97 | options_list["config"]=arg 98 | 99 | if opt in ("-b", "--backup"): 100 | backup_mode=True 101 | backup_file = arg 102 | output_type = "BACKUP" 103 | options_list["backup"]=arg 104 | 105 | if opt in ("-r", "--restore"): 106 | restore_mode=True 107 | backup_file = arg 108 | options_list["restore"]=arg 109 | 110 | if opt in ("-h", "--help"): 111 | show_help = True 112 | options_list["help"]="" 113 | 114 | elif opt in ("-d", "--driver"): 115 | driver = arg.upper() 116 | options_list["driver"]=arg.upper() 117 | 118 | elif opt in ("-p", "--port"): 119 | port = arg 120 | options_list["port"]=arg 121 | 122 | elif opt in ("-c", "--cmd"): 123 | cmd.append(arg) 124 | 125 | elif opt in ("-v", "--verbose"): 126 | verbose = arg 127 | options_list["verbose"]="" 128 | 129 | elif opt in ("-o", "--output_type"): 130 | output_type = arg.upper() 131 | options_list["output_type"]=arg.upper() 132 | 133 | elif opt in ("-l", "--language"): 134 | lg_code = arg.upper() 135 | options_list["language"]=arg.upper() 136 | 137 | elif opt in ("-g", "--log"): 138 | logger = logging.getLogger('pyhpsu') 139 | hdlr = logging.FileHandler(arg) 140 | formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') 141 | hdlr.setFormatter(formatter) 142 | logger.addHandler(hdlr) 143 | logger.setLevel(logging.ERROR) 144 | options_list["cmd"]=cmd 145 | if verbose == "2": 146 | locale.setlocale(locale.LC_ALL, '') 147 | 148 | # config if in auto mode 149 | if auto: 150 | read_from_conf_file=True 151 | conf_file=default_conf_file 152 | 153 | # get config from file if given.... 154 | if read_from_conf_file: 155 | if conf_file==None: 156 | print("Error, please provide a config file") 157 | sys.exit(9) 158 | else: 159 | try: 160 | with open(conf_file) as f: 161 | config.read_file(f) 162 | except IOError: 163 | print("Error: config file not found") 164 | sys.exit(9) 165 | config.read(conf_file) 166 | if driver=="" and config.has_option('PYHPSU','PYHPSU_DEVICE'): 167 | driver=config['PYHPSU']['PYHPSU_DEVICE'] 168 | if port=="" and config.has_option('PYHPSU','PYHPSU_PORT'): 169 | port=config['PYHPSU']['PYHPSU_PORT'] 170 | if lg_code=="" and config.has_option('PYHPSU','PYHPSU_LANG'): 171 | lg_code=config['PYHPSU']['PYHPSU_LANG'] 172 | if output_type=="" and config.has_option('PYHPSU','OUTPUT_TYPE'): 173 | output_type=config['PYHPSU']['OUTPUT_TYPE'] 174 | 175 | else: 176 | conf_file=default_conf_file 177 | if output_type=="": 178 | output_type="JSON" 179 | # 180 | # now we should have all options...let's check them 181 | # 182 | # Check driver 183 | if driver not in ["ELM327", "PYCAN", "EMU", "HPSUD"]: 184 | print("Error, please specify a correct driver [ELM327, PYCAN, EMU, HPSUD] ") 185 | sys.exit(9) 186 | 187 | if driver == "ELM327" and port == "": 188 | print("Error, please specify a correct port for the ELM327 device ") 189 | sys.exit(9) 190 | 191 | # Check output type 192 | if output_type not in PLUGIN_LIST: 193 | print("Error, please specify a correct output_type [" + PLUGIN_STRING + "]") 194 | sys.exit(9) 195 | 196 | # Check Language 197 | if lg_code not in languages: 198 | print("Error, please specify a correct language [%s]" % " ".join(languages)) 199 | sys.exit(9) 200 | # ------------------------------------ 201 | # try to query different commands in different periods 202 | # Read them from config and group them 203 | # 204 | # create dictionary for the jobs 205 | if auto: 206 | timed_jobs=dict() 207 | if read_from_conf_file: # if config is read from file 208 | if len(config.options('JOBS')): # if there are configured jobs 209 | for each_key in config.options('JOBS'): # for each value to query 210 | job_period=config.get('JOBS',each_key) # get the period 211 | if not "timer_" + job_period in timed_jobs.keys(): # if this period isn't still in the dict 212 | timed_jobs["timer_" + job_period]=[] # create a list for this period 213 | timed_jobs["timer_" + job_period].append(each_key) # and add the value to this period 214 | wanted_periods=list(timed_jobs.keys()) 215 | else: 216 | print("Error, please specify a value to query in config file ") 217 | sys.exit(9) 218 | 219 | # 220 | # Print help 221 | # 222 | if show_help: 223 | n_hpsu = HPSU(driver=driver, logger=logger, port=port, cmd=cmd, lg_code=lg_code) 224 | if len(cmd) == 0: 225 | print("List available commands:") 226 | print("%20s - %-10s" % ('COMMAND', 'LABEL')) 227 | print("%20s---%-10s" % ('------------', '----------')) 228 | for cmd in sorted(n_hpsu.command_dict) : 229 | try: 230 | print("%20s - %-10s" % (n_hpsu.command_dict[cmd]['name'], n_hpsu.command_dict[cmd]['label'])) 231 | except KeyError: 232 | print("""!!!!!! No translation for "%12s" !!!!!!!""" % (n_hpsu.command_dict[cmd]['name'])) 233 | else: 234 | print("%12s - %-10s - %s" % ('COMMAND', 'LABEL', 'DESCRIPTION')) 235 | print("%12s---%-10s---%s" % ('------------', '----------', '---------------------------------------------------')) 236 | for c in n_hpsu.commands: 237 | print("%12s - %-10s - %s" % (c['name'], c['label'], c['desc'])) 238 | sys.exit(0) 239 | 240 | # 241 | # now its time to call the hpsu and do the REAL can query 242 | # and handle the data as configured 243 | # 244 | if auto and not backup_mode: 245 | while loop: 246 | ticker+=1 247 | collected_cmds=[] 248 | for period_string in timed_jobs.keys(): 249 | period=period_string.split("_")[1] 250 | if not ticker % int(period): 251 | for job in timed_jobs[period_string]: 252 | collected_cmds.append(str(job)) 253 | if len(collected_cmds): 254 | n_hpsu = HPSU(driver=driver, logger=logger, port=port, cmd=collected_cmds, lg_code=lg_code) 255 | exec('thread_%s = threading.Thread(target=read_can, args=(driver,logger,port,collected_cmds,lg_code,verbose,output_type))' % (period)) 256 | exec('thread_%s.start()' % (period)) 257 | time.sleep(1) 258 | elif backup_mode: 259 | n_hpsu = HPSU(driver=driver, logger=logger, port=port, cmd=cmd, lg_code=lg_code) 260 | read_can(driver, logger, port, n_hpsu.backup_commands, lg_code,verbose,output_type) 261 | elif restore_mode: 262 | restore_commands=[] 263 | try: 264 | with open(backup_file, 'rU') as jsonfile: 265 | restore_settings=json.load(jsonfile) 266 | for command in restore_settings: 267 | restore_commands.append(str(command["name"]) + ":" + str(command["resp"])) 268 | n_hpsu = HPSU(driver=driver, logger=logger, port=port, cmd=restore_commands, lg_code=lg_code) 269 | read_can(driver, logger, port, restore_commands, lg_code,verbose,output_type) 270 | except FileNotFoundError: 271 | print("No such file or directory!!!") 272 | sys.exit(1) 273 | 274 | else: 275 | n_hpsu = HPSU(driver=driver, logger=logger, port=port, cmd=cmd, lg_code=lg_code) 276 | read_can(driver, logger, port, cmd, lg_code,verbose,output_type) 277 | 278 | def read_can(driver,logger,port,cmd,lg_code,verbose,output_type): 279 | global backup_file 280 | # really needed? Driver is checked above 281 | #if not driver: 282 | # print("Error, please specify driver [ELM327 or PYCAN, EMU, HPSUD]") 283 | # sys.exit(9) 284 | 285 | arrResponse = [] 286 | 287 | for c in n_hpsu.commands: 288 | setValue = None 289 | for i in cmd: 290 | if ":" in i and c["name"] == i.split(":")[0]: 291 | setValue = i.split(":")[1] 292 | if not c["type"] == "value": 293 | setValue = float(setValue)*float(c["divisor"]) 294 | else: 295 | if not setValue.isdigit(): 296 | key=str(setValue) 297 | setValue=c["value_code"][str(setValue)] 298 | 299 | i = 0 300 | while i <= 3: 301 | rc = n_hpsu.sendCommand(c, setValue) 302 | if rc != "KO": 303 | i = 4 304 | if not setValue: 305 | response = n_hpsu.parseCommand(cmd=c, response=rc, verbose=verbose) 306 | resp = n_hpsu.umConversion(cmd=c, response=response, verbose=verbose) 307 | 308 | arrResponse.append({"name":c["name"], "resp":resp, "timestamp":response["timestamp"]}) 309 | else: 310 | i += 1 311 | time.sleep(2.0) 312 | n_hpsu.printd('warning', 'retry %s command %s' % (i, c["name"])) 313 | if i == 4: 314 | n_hpsu.printd('error', 'command %s failed' % (c["name"])) 315 | 316 | if output_type == "JSON": 317 | if len(arrResponse)!=0: 318 | arrResponse = json.dumps(arrResponse) 319 | print(arrResponse) 320 | elif output_type == "CSV": 321 | for r in arrResponse: 322 | print("%s,%s,%s" % (r["timestamp"], r["name"], r["resp"])) 323 | elif output_type == "BACKUP": 324 | print("Writing Backup to " + str(backup_file)) 325 | try: 326 | with open(backup_file, 'w') as outfile: 327 | json.dump(arrResponse, outfile, sort_keys = True, indent = 4, ensure_ascii = False) 328 | except FileNotFoundError: 329 | print("No such file or directory!!!") 330 | sys.exit(1) 331 | else: 332 | module_name=output_type.lower() 333 | module = importlib.import_module("HPSU.plugins." + module_name) 334 | hpsu_plugin = module.export(hpsu=n_hpsu, logger=logger, config_file=conf_file) 335 | hpsu_plugin.pushValues(vars=arrResponse) 336 | 337 | if __name__ == "__main__": 338 | main(sys.argv[1:]) 339 | -------------------------------------------------------------------------------- /pyHPSUd.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # v 0.0.4 by Vanni Brutto (Zanac) 5 | # DONT use CTRL+C to Terminate, else Port is blocked 6 | 7 | import pika 8 | #import threading 9 | import serial 10 | import time 11 | import sys 12 | #sys.path.append('/usr/share/pyHPSU/HPSU/'); 13 | #sys.path.append('/usr/share/pyHPSU/plugins/'); 14 | import getopt 15 | import logging 16 | import json 17 | from HPSU.HPSU import HPSU 18 | 19 | 20 | #------------------------------------------------------------------- 21 | DEBUG = True 22 | DEBUG = False 23 | verbose = "1" 24 | logger = None 25 | #------------------------------------------------------------------- 26 | 27 | try: 28 | DEBUG 29 | except NameError: 30 | DEBUG = False 31 | 32 | if DEBUG: 33 | print("Enabling DEBUG mode!") 34 | 35 | def printD(message): 36 | if DEBUG: 37 | print(message) 38 | sys.stdout.flush() 39 | 40 | 41 | class MainHPSU(object): 42 | def main2(self, argv): 43 | cmd = [] 44 | driver = None 45 | verbose = "1" 46 | help = False 47 | port = None 48 | lg_code = None 49 | languages = ["EN", "IT", "DE"] 50 | 51 | try: 52 | opts, args = getopt.getopt(argv,"hp:d:v:l:g:", ["help", "port=", "driver=", "verbose=", "language=", "log="]) 53 | except getopt.GetoptError: 54 | print('pyHPSUd.py -d DRIVER') 55 | print(' ') 56 | print(' -d --driver driver name: [ELM327, PYCAN, EMU]') 57 | print(' -p --port port (eg COM or /dev/tty*, only for ELM327 driver)') 58 | print(' -v --verbose verbosity: [1, 2] default 1') 59 | print(' -l --language set the language to use [%s]' % " ".join(languages) ) 60 | print(' -g --log set the log to file [_filename]') 61 | sys.exit(2) 62 | 63 | for opt, arg in opts: 64 | if opt in ("-h", "--help"): 65 | help = True 66 | elif opt in ("-d", "--driver"): 67 | driver = arg.upper() 68 | elif opt in ("-p", "--port"): 69 | port = arg 70 | elif opt in ("-v", "--verbose"): 71 | verbose = arg 72 | elif opt in ("-l", "--language"): 73 | lg_code = arg.upper() 74 | if lg_code not in languages: 75 | print("Error, please specify a correct language [%s]" % " ".join(languages)) 76 | sys.exit(9) 77 | elif opt in ("-g", "--log"): 78 | logger = logging.getLogger('pyHPSUd') 79 | hdlr = logging.FileHandler(arg) 80 | formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') 81 | hdlr.setFormatter(formatter) 82 | logger.addHandler(hdlr) 83 | logger.setLevel(logging.WARNING) 84 | 85 | self.hpsu = HPSU(driver=driver, logger=None, port=port, cmd=cmd, lg_code=lg_code) 86 | connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) 87 | channel = connection.channel() 88 | 89 | channel.queue_delete(queue='hpsu_queue') 90 | channel.queue_declare(queue='hpsu_queue', arguments={"x-max-priority":3}) 91 | channel.basic_qos(prefetch_count=1) 92 | channel.basic_consume(self.on_request, queue='hpsu_queue') 93 | channel.start_consuming() 94 | 95 | def on_request(self, ch, method, props, body): 96 | message = json.loads(body.decode('UTF-8')) 97 | name = message["name"] 98 | value = message["value"] 99 | type = message["type"] 100 | 101 | rc = "KO" 102 | for cmd in self.hpsu.commands: 103 | if name == cmd["name"]: 104 | rc = self.hpsu.sendCommand(cmd, value, cmd["type"]) 105 | 106 | if type == "sync": 107 | priority = 2 108 | response = rc 109 | ch.basic_publish(exchange='', 110 | routing_key=props.reply_to, 111 | properties=pika.BasicProperties(priority=priority, correlation_id = props.correlation_id), 112 | body=str(response)) 113 | ch.basic_ack(delivery_tag = method.delivery_tag) 114 | 115 | def _exit(): 116 | try: 117 | read_thread.exit() 118 | socket_server_thread.exit() 119 | sys.exit() 120 | except (Exception, e3): 121 | exit() 122 | 123 | if __name__ == '__main__': 124 | #main(sys.argv[1:]) 125 | main = MainHPSU() 126 | main.main2(sys.argv[1:]) 127 | 128 | -------------------------------------------------------------------------------- /resources/pyHPSU-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Spanni26/pyHPSU/14e784b222da5957df2cd5a9282d1534ffaf7ab7/resources/pyHPSU-logo.jpg -------------------------------------------------------------------------------- /resources/pyHPSU-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Spanni26/pyHPSU/14e784b222da5957df2cd5a9282d1534ffaf7ab7/resources/pyHPSU-logo.png -------------------------------------------------------------------------------- /systemd/hpsu.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=HPSU in auto mode 3 | #Requires=influxd.service 4 | 5 | [Service] 6 | Type=simple 7 | ExecStartPre= 8 | EnvironmentFile=/etc/pyHPSU/pyhpsu.conf 9 | ExecStart=/usr/bin/pyHPSU.py -a 10 | ExecReload= 11 | ExecStop= 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | Alias=hpsu.service 16 | -------------------------------------------------------------------------------- /systemd/hpsud.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=HPSUD 3 | After=network.target rabbitmq-server.service 4 | Requires=rabbitmq-server.service 5 | 6 | [Service] 7 | Type=simple 8 | ExecStartPre= 9 | EnvironmentFile=/etc/pyHPSU/pyhpsu.conf 10 | ExecStart=/usr/bin/pyHPSUd.py -d ${PYHPSUD_DEVICE} -l ${PYHPSUD_LANG} -p ${PYHPSUD_PORT} 11 | ExecReload= 12 | ExecStop= 13 | 14 | [Install] 15 | WantedBy=multi-user.target 16 | Alias=hpsud.service 17 | 18 | --------------------------------------------------------------------------------