Skip to content

Instantly share code, notes, and snippets.

@denpamusic
Last active April 24, 2022 15:30
Show Gist options
  • Save denpamusic/6375c2a57716dc42861350f0eebc1e68 to your computer and use it in GitHub Desktop.
Save denpamusic/6375c2a57716dc42861350f0eebc1e68 to your computer and use it in GitHub Desktop.
ecomax.py file from official ecoNET 300 firmware
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
import threading
import traceback
from operator import attrgetter
import logging
import datetime
import struct
import zlib
import queue
import copy
import crcLib
import state
import param
import settings
import utils
import datafile
import regSoftUpdater as rsu
import pfc_file
logger=logging.getLogger('econet.ecomax')
mutex=threading.Lock()
BEGIN_FRAME='\x68'
END_FRAME='\x16'
ECONET_VERSION='\x05'
SENDER_ADDR_ECONET='\x56'
SENDER_ADDR_ECOSTER='\x51'
SENDER_ADDR_BROADCAST='\x00'
SENDER_TYPE_ECONET='\x30'
SENDER_ADDR_ECOSTERS=['\x51','\x57','\x58']
FRAME_CHECK_DEVICE='\x30'
FRAME_DEVICE_AVAILABLE='\xB0'
FRAME_DATA_ANS='\x35'
FRAME_GET_PARAMS='\x31'
FRAME_GET_PARAMS_ANS='\xB1'
FRAME_GET_MIXERS_PARAMS='\x32'
FRAME_GET_MIXER_PARAMS_ANS='\xB2'
FRAME_SET_PARAM='\x33'
FRAME_SET_PARAM_ANS='\xB3'
FRAME_SET_ECOSTER_PARAM='\x5D'
FRAME_SET_ECOSTER_PARAM_ANS='\xDD'
FRAME_SET_MIXER_PARAM='\x34'
FRAME_SET_MIXER_PARAM_ANS='\xB4'
FRAME_GET_TIME_ZONES='\x36'
FRAME_GET_TIME_ZONESANS='\xB6'
FRAME_SET_TIME_ZONES='\x37'
FRAME_GET_SETTINGS='\x38'
FRAME_GET_SETTINGS_ANS='\xB8'
FRAME_GET_UID='\x39'
FRAME_GET_UID_ANS='\xB9'
FRAME_GET_PASSWD='\x3A'
FRAME_GET_PASSWD_ANS='\xBA'
FRAME_SET_WIFI='\x3C'
FRAME_SET_WIFI_ANS='\xBC'
FRAME_GET_ALARMS='\x3D'
FRAME_GET_ALARMS_ANS='\xBD'
FRAME_SET_BOILER_CONTOL='\x3B'
FRAME_SET_BOILER_CONTOL_ANS='\xBB'
FRAME_SET_ECOSTER_SCHEDULES='\x59'
FRAME_SET_ECOSTER_SCHEDULES_ANS='\xD9'
FRAME_GET_PARAMS_CONF='\x50'
FRAME_GET_PARAMS_CONF_ANS='\xD0'
FRAME_GET_MIXERS_CONF='\x51'
FRAME_GET_MIXERS_CONF_ANS='\xD1'
FRAME_GET_PARAMS_STRUCT='\x52'
FRAME_GET_PARAMS_STRUCT_ANS='\xD2'
FRAME_GET_MIXERS_STRUCT='\x53'
FRAME_GET_MIXERS_STRUCT_ANS='\xD3'
FRAME_GET_ECOSTER_PARAMS='\x5C'
FRAME_GET_ECOSTER_PARAMS_ANS='\xDC'
FRAME_GET_ECOSTER_CONF='\x5E'
FRAME_GET_ECOSTER_CONF_ANS='\xDE'
FRAME_GET_ECOSTER_STRUCT='\x5F'
FRAME_GET_ECOSTER_STRUCT_ANS='\xDF'
FRAME_GET_NAMES='\x3E'
FRAME_GET_NAMES_ANS='\xBE'
FRAME_GET_ECOSTER_SCHEDULES='\x58'
FRAME_GET_ECOSTER_SCHEDULES_ANS='\xD8'
FRAME_PROGRAM_VERSION='\x40'
FRAME_PROGRAM_VERSION_ANS='\xC0'
FRAME_ENTER_LOADER='\x60'
FRAME_ENTER_LOADER_ANS='\xE0'
FRAME_CONFIRM_LOADER='\x61'
FRAME_CONFIRM_LOADER_ANS='\xE1'
FRAME_DELETE_SOFTWARE='\x62'
FRAME_DELETE_SOFTWARE_ANS='\xE2'
FRAME_SAVE_FLASH='\x63'
FRAME_SAVE_FLASH_ANS='\xE3'
FRAME_VERIFY_PROGRAM='\x65'
FRAME_VERIFY_PROGRAM_ANS='\xE5'
FRAME_LEAVE_LOADER='\x66'
FRAME_LEAVE_LOADER_ANS='\xE6'
FRAME_VERIFY_SOFT='\x64'
FRAME_VERIFY_SOFT_ANS='\xE4'
FRAME_SOFT_INCOMPATIBLE='\x79'
FRAME_NO_INIT_DATA_ERROR='\x7A'
FRAME_AUTOIDENT_DATA_ERROR='\x7B'
FRAME_KRYPTOGRAPHIC_ERROR='\x7C'
FRAME_ADDRESS_ERROR='\x7D'
FRAME_DATA_SIZE_ERROR='\x7E'
FRAME_ERROR_FRAME='\x7F'
FRAME_STOP_MASTER='\x18'
FRAME_START_MASTER='\x19'
FRAME_GET_CURRPARAMS='\x54'
FRAME_GET_CURRPARAMS_ANS='\xD4'
FRAME_GET_CURRPARAMSCONSTR='\x55'
FRAME_GET_CURRPARAMSCONSTR_ANS='\xD5'
FRAME_REMOTE_MENU='\x56'
FRAME_REMOTE_MENU_ANS='\xD6'
FRAME_SET_CURRPARAM='\x57'
FRAME_SET_CURRPARAM_ANS='\xD7'
FRAME_GET_CONFIG_SCHEMA='\x1A'
FRAME_GET_CONFIG_SCHEMA_ANS='\x9A'
FRAME_GET_CONFIG_CURRENT_EDIT='\x61'
FRAME_GET_CONFIG_CURRENT_EDIT_ANS='\xE1'
FRAME_GET_CONFIG_COMMON='\x21'
FRAME_GET_CONFIG_COMMON_ANS='\xA1'
FRAME_GET_CONFIG_TEXTS='\x62'
FRAME_GET_CONFIG_TEXTS_ANS='\xE2'
FRAME_GET_CONFIG_NOEDIT='\x63'
FRAME_GET_CONFIG_NOEDIT_ANS='\xE3'
FRAME_GET_CONFIG_BURNERS='\x17'
FRAME_GET_CONFIG_BURNERS_ANS='\x97'
FRAME_GET_CONFIG_BURNERS_NOINDEX_ANS='\xFF'
FRAME_SET_CONFIG_CURRENT_EDIT='\x70'
FRAME_SET_CONFIG_CURRENT_EDIT_ANS='\xF0'
FRAME_SET_CONFIG_COMMON_VALS='\x11'
FRAME_SET_CONFIG_COMMON_VALS_ANS='\x91'
FRAME_SET_CONFIG_COMMON='\x12'
FRAME_SET_CONFIG_COMMON_ANS='\x92'
FRAME_SET_CONFIG_TEXTS='\x13'
FRAME_SET_CONFIG_TEXTS_ANS='\x93'
FRAME_SET_CONFIG_NOEDIT='\x14'
FRAME_SET_CONFIG_NOEDIT_ANS='\x94'
FRAME_SET_CONFIG_BURNERS='\x15'
FRAME_SET_CONFIG_BURNERS_ANS='\x95'
FRAME_SET_CONFIG_EEPROM_CL='\x16'
FRAME_SET_CONFIG_EEPROM_CL_ANS='\x96'
PATTERN_GET_CONFIG_FABRIC_FRAMES=[FRAME_SET_CONFIG_COMMON_VALS,FRAME_SET_CONFIG_COMMON,FRAME_GET_CONFIG_TEXTS,FRAME_GET_CONFIG_NOEDIT,FRAME_GET_CONFIG_BURNERS]
PATTERN_GET_CONFIG_FRAMES=[[FRAME_GET_CONFIG_SCHEMA,'\x01'],[FRAME_GET_CONFIG_SCHEMA,'\x02'],[FRAME_GET_CONFIG_CURRENT_EDIT,'\xFF','\x00'],[FRAME_GET_CONFIG_COMMON],[FRAME_GET_CONFIG_TEXTS],[FRAME_GET_CONFIG_NOEDIT],[FRAME_GET_CONFIG_BURNERS]]
PATTERN_GET_CONFIG_FRAMES_ANS=[[FRAME_GET_CONFIG_SCHEMA_ANS,'\x01'],[FRAME_GET_CONFIG_SCHEMA_ANS,'\x02'],[FRAME_GET_CONFIG_CURRENT_EDIT_ANS],[FRAME_GET_CONFIG_COMMON_ANS],[FRAME_GET_CONFIG_TEXTS_ANS],[FRAME_GET_CONFIG_NOEDIT_ANS],[FRAME_GET_CONFIG_BURNERS_ANS]]
PATTERN_SET_CONFIG_FRAMES=[pfc_file.PfcFile.PFC_SECTION_FABR_DATA,pfc_file.PfcFile.PFC_SECTION_CURR_DATA]
SET_CONFIG_FRAMES_MAP=[[FRAME_SET_CONFIG_COMMON_VALS,FRAME_SET_CONFIG_COMMON_VALS_ANS],[FRAME_SET_CONFIG_COMMON,FRAME_SET_CONFIG_COMMON_ANS],[FRAME_SET_CONFIG_TEXTS,FRAME_SET_CONFIG_TEXTS_ANS],[FRAME_SET_CONFIG_NOEDIT,FRAME_SET_CONFIG_NOEDIT_ANS],[FRAME_SET_CONFIG_BURNERS,FRAME_SET_CONFIG_BURNERS_ANS],[FRAME_SET_CONFIG_CURRENT_EDIT,FRAME_SET_CONFIG_CURRENT_EDIT_ANS],[FRAME_SET_CONFIG_EEPROM_CL,FRAME_SET_CONFIG_EEPROM_CL_ANS]]
ECONET_REQUEST_FRAMES_LIST=[FRAME_GET_TIME_ZONES,FRAME_GET_SETTINGS,FRAME_GET_UID,FRAME_GET_PASSWD,FRAME_GET_ALARMS,FRAME_GET_PARAMS,FRAME_GET_PARAMS_CONF,FRAME_GET_PARAMS_STRUCT,FRAME_GET_MIXERS_PARAMS,FRAME_GET_MIXERS_CONF,FRAME_GET_MIXERS_STRUCT,FRAME_GET_ECOSTER_PARAMS,FRAME_GET_ECOSTER_CONF,FRAME_GET_ECOSTER_STRUCT,FRAME_GET_NAMES,FRAME_GET_ECOSTER_SCHEDULES,FRAME_GET_CURRPARAMS,FRAME_GET_CURRPARAMSCONSTR,FRAME_REMOTE_MENU,]
CONFIG_PROCESS_RESUME_COUNT=3
FRAME_REGDATA_ANS='\x08'
REGDATA_VERSION='1.0'
ECONET_IMAGE=[]
REMOTE_MENU_FRAMES='\x54\x55\x56'
FRAME_REG_PARAMS='\x31'
REMOTE_MENU_NEWPARAM_COMMAND=5
REMOTE_MENU_NOPASSWORD=0
REMOTE_MENU_PASS1=32
REMOTE_MENU_PASS2=64
REMOTE_MENU_PASS3=96
REMOTE_MENU_PASS4=128
REMOTE_MENU_PASS5=160
REMOTE_MENU_PASS6=192
REMOTE_MENU_PASS7=224
REMOTE_MENU_CAT_ELEMENT=0
REMOTE_MENU_PARAM_ELEMENT=1
REMOTE_MENU_CURRDATACAT_ELEMENT=2
REMOTE_MENU_CURRDATA_ELEMENT=3
REMOTE_MENU_ALARMSCAT_ELEMENT=4
REMOTE_MENU_PASSWORD_ELEMENT=5
REMOTE_MENU_LOCK_ELEMENT=6
REMOTE_MENU_CHILDCOUNTER_ELEMENT=7
REMOTE_MENU_LOCK=16
REMOTE_MENU_VERSION='1.0'
REMOTE_MENU_ALLOWED_COMMANDS=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
REMOTE_MENU_LANG_COMMANDS=[2,6,7,8,11,12,13,14,15]
REMOTE_MENU_CONSTANT_ELEMENTS={1280:'CO_TEMP_SET',1281:'CWU_SET_TEMP'}
IGNORE_FRAMES=()
ECOMAX850P=0
ECOMAX850i=1
ECOMAX_REGULATOR=0
ECOMAX_INSTALACYJNY=1
MODIFY_PARAM_ATTEMPTS=10
SCHEDULE_MIN_VERSION='\x10'
REMOTE_MENU_SEND_LANG_MAX_COUNT=3
REMOTE_MENU_REPEAT_IN_PARSECURRENT_COUNT=20
MODULE_A_CONT_ADDRESS='\x45'
ECOMAXDATA_TEMP_MEMBER_NAMES=('tempCO','tempFeeder','tempCWU','tempExternalSensor','tempBack','tempFlueGas','tempOpticalSensor','tempUpperBuffer','tempLowerBuffer','tempUpperSolar','tempLowerSolar','tempFireplace','totalGain','tempHydraulicCoupler','tempExchanger','tempAirIn','tempAirOut')
ECOMAXDATA_TIMEZONES_TYPES=['boilerTZ','cwuTZ','circPumpTZ','boilerWorkTZ','boilerCleanTZ','exchangerCleanTZ','mixer1TZ','mixer2TZ','mixer3TZ','mixer4TZ','mixer5TZ','mixer6TZ','mixer7TZ','mixer8TZ','mixer9TZ','mixer10TZ','thermostat1TZ','thermostat2TZ','thermostat3TZ','circuit1TZ','circuit2TZ','circuit3TZ','circuit4TZ','circuit5TZ','circuit6TZ','circuit7TZ','panel1TZ','panel2TZ','panel3TZ','panel4TZ','panel5TZ','panel6TZ','panel7TZ','mainHeSoTZ','heatCirc','embeddedThermo','heater','cwu2TZ','intake','intakeSummer']
ECOSTER_TIMESONES_TYPES=['thermostat1TZ','thermostat2TZ','thermostat3TZ']
ECOMAX_TIMEZONES_TYPES=['boilerTZ','cwuTZ','circPumpTZ','boilerWorkTZ','boilerCleanTZ','mixer1TZ','mixer2TZ','mixer3TZ','mixer4TZ','mixer5TZ','mixer6TZ','mixer7TZ','mixer8TZ','mixer9TZ','mixer10TZ','circuit1TZ','circuit2TZ','circuit3TZ','circuit4TZ','circuit5TZ','circuit6TZ','circuit7TZ','panel1TZ','panel2TZ','panel3TZ','panel4TZ','panel5TZ','panel6TZ','panel7TZ','mainHeSoTZ']
CURRENT_DATA_TYPES_LEN=[0,1,2,4,1,2,4,4,0,8,1,-1,-1,8,8,4,16]
CURRENT_DATATYPE_UNDEFINED0=0
CURRENT_DATATYPE_SHORT_INT=1
CURRENT_DATATYPE_INT=2
CURRENT_DATATYPE_LONG_INT=3
CURRENT_DATATYPE_BYTE=4
CURRENT_DATATYPE_WORD=5
CURRENT_DATATYPE_DWORD=6
CURRENT_DATATYPE_SHORT_REAL=7
CURRENT_DATATYPE_UNDEVINED8=8
CURRENT_DATATYPE_LONG_REAL=9
CURRENT_DATATYPE_BOOLEAN=10
CURRENT_DATATYPE_BCD=11
CURRENT_DATATYPE_STRING=12
CURRENT_DATATYPE_INT_64=13
CURRENT_DATATYPE_UINT_64=14
CURRENT_DATATYPE_IPv4=15
CURRENT_DATATYPE_IPv6=16
PARAMETERS_WITH_OFF_POSSIBILITY=['MIN_T_COLLECTOR','MAX_T_COLLECTOR','TEMP_OFF_COLLECTOR','MIN_ROT_SOLAR','SOLAR_ANTIFREEZ']
ECOMAX_200_DEVID=0x03
ECOMAX_250R_DEVID=0x0E
ECOMAX_250R_FL_DEVID=0x18
ECOMAX_250W_DEVID=0x0D
SPARK_820X_MODA_DEVID=0x56
SPARK_820X_PANEL_DEVID=0x57
ECOMAX_800R_MODA_DEVID=0x37
ECOMAX_800R_PANEL_DEVID=0x38
CONDITIONAL_TILES_EXTRAS={'tempCWU':[None,{'addParameters':'CWU_WORK_MODE','index':'1'}],'mixerTemp1':[None,{'addParameters':'WORK_MODE_H_1','index':'1'}],'mixerTemp2':[None,{'addParameters':'WORK_MODE_H_2','index':'2'}],'mixerTemp3':[None,{'addParameters':'WORK_MODE_H_3','index':'3'}],'mixerTemp4':[None,{'addParameters':'WORK_MODE_H_4','index':'4'}],'mixerTemp5':[None,{'addParameters':'WORK_MODE_H_5','index':'5'}],'mixerTemp6':[None,{'addParameters':'WORK_MODE_H_6','index':'6'}],'mixerTemp7':[None,{'addParameters':'WORK_MODE_H_7','index':'7'}],'mixerTemp8':[None,{'addParameters':'WORK_MODE_H_8','index':'8'}]}
AVAILABLE_TILES={ECOMAX850P:[state.TileConfig(state.TileConfig.TYPE_TEMP,'tempCO','tempCOSet',0,100,10),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempFeeder',None,0,100),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempFlueGas',None,0,450,8),state.TileConfig(state.TileConfig.TYPE_TEMP,'tempCWU','tempCWUSet',0,100,12),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempExternalSensor',None,-35,40,13),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempBack',None,0,100,11),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempUpperBuffer',None,0,100,14),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempLowerBuffer',None,0,100,15),state.TileConfig(state.TileConfig.TYPE_TEMP_WAVE,'ecoSterTemp1','ecoSterSetTemp1',0,100,None,{'tempSelection':'ecoSterContacts1','addParameters':'STER_MODE_1;WORK_MODE_H_1','index':'1'}),state.TileConfig(state.TileConfig.TYPE_TEMP_WAVE,'ecoSterTemp2','ecoSterSetTemp2',0,100,None,{'tempSelection':'ecoSterContacts2','addParameters':'STER_MODE_2;WORK_MODE_H_2','index':'2'}),state.TileConfig(state.TileConfig.TYPE_TEMP_WAVE,'ecoSterTemp3','ecoSterSetTemp3',0,100,None,{'tempSelection':'ecoSterContacts3','addParameters':'STER_MODE_3;WORK_MODE_H_3','index':'3'}),state.TileConfig(state.TileConfig.TYPE_TEMP_WAVE,'ecoSterTemp4','ecoSterSetTemp4',0,100,None,{'tempSelection':'ecoSterContacts4','addParameters':'STER_MODE_4;WORK_MODE_H_4','index':'4'}),state.TileConfig(state.TileConfig.TYPE_TEMP_WAVE,'ecoSterTemp5','ecoSterSetTemp5',0,100,None,{'tempSelection':'ecoSterContacts5','addParameters':'STER_MODE_5;WORK_MODE_H_5','index':'5'}),state.TileConfig(state.TileConfig.TYPE_TEMP_WAVE,'ecoSterTemp6','ecoSterSetTemp6',0,100,None,{'tempSelection':'ecoSterContacts6','addParameters':'STER_MODE_6;WORK_MODE_H_6','index':'6'}),state.TileConfig(state.TileConfig.TYPE_TEMP_WAVE,'ecoSterTemp7','ecoSterSetTemp7',0,100,None,{'tempSelection':'ecoSterContacts7','addParameters':'STER_MODE_7;WORK_MODE_H_7','index':'7'}),state.TileConfig(state.TileConfig.TYPE_TEMP_WAVE,'ecoSterTemp8','ecoSterSetTemp8',0,100,None,{'tempSelection':'ecoSterContacts8','addParameters':'STER_MODE_8;WORK_MODE_H_8','index':'8'}),state.TileConfig(state.TileConfig.TYPE_TEMP,'mixerTemp1','mixerSetTemp1',0,100,16),state.TileConfig(state.TileConfig.TYPE_TEMP,'mixerTemp2','mixerSetTemp2',0,100,17),state.TileConfig(state.TileConfig.TYPE_TEMP,'mixerTemp3','mixerSetTemp3',0,100,18),state.TileConfig(state.TileConfig.TYPE_TEMP,'mixerTemp4','mixerSetTemp4',0,100,19),state.TileConfig(state.TileConfig.TYPE_TEMP,'mixerTemp5','mixerSetTemp5',0,100,20),state.TileConfig(state.TileConfig.TYPE_TEMP,'mixerTemp6','mixerSetTemp6',0,100,21),state.TileConfig(state.TileConfig.TYPE_TEMP,'mixerTemp7','mixerSetTemp7',0,100,22),state.TileConfig(state.TileConfig.TYPE_TEMP,'mixerTemp8','mixerSetTemp8',0,100,23),state.TileConfig(state.TileConfig.TYPE_FLAME,'tempOpticalSensor',None,0,100,7),state.TileConfig(state.TileConfig.TYPE_TEXT_ICON,'lambdaLevel',None,0,100,9),state.TileConfig(state.TileConfig.TYPE_LEVEL,'fuelLevel',None,0,100,4),state.TileConfig(state.TileConfig.TYPE_STREAM,'fuelStream',None,0,100,5),state.TileConfig(state.TileConfig.TYPE_POWER,'boilerPower',None,0,100,3),state.TileConfig(state.TileConfig.TYPE_FAN,'fanPower',None,0,100,6),state.TileConfig(state.TileConfig.TYPE_FAN,'fanPowerExhaust',None,0,100),state.TileConfig(state.TileConfig.TYPE_TEXT,'mode',None,0,100,1,state.CANNOT_CONTROL_BOILER),state.TileConfig(state.TileConfig.TYPE_NONE,'none1'),state.TileConfig(state.TileConfig.TYPE_NONE,'none2'),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempUpperSolar',None,0,100,24),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempLowerSolar',None,0,100,25),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempFireplace',None,0,100,26),state.TileConfig(state.TileConfig.TYPE_NONE,'fuelCons'),state.TileConfig(state.TileConfig.TYPE_TEXT,'totalGain',None,0,None,2),state.TileConfig(state.TileConfig.TYPE_NONE,'none5'),state.TileConfig(state.TileConfig.TYPE_TEMP,'thermoTemp','thermoSetTemp',0,100,None,{'addParameters':'WORK_MODE_H_1','index':'1'}),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempExchanger',None,0,100,None,{'addParameters':'WORK_MODE_H_2','index':'2'}),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempAirIn',None,0,100,None,{'addParameters':'WORK_MODE_H_3','index':'3'}),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempAirOut',None,0,100,None,{'addParameters':'WORK_MODE_H_4','index':'4'}),state.TileConfig(state.TileConfig.TYPE_FAN,'blowFan1BlowPower',None,0,100,None,{'addParameters':'WORK_MODE_H_5','index':'5'}),state.TileConfig(state.TileConfig.TYPE_FAN,'blowFan2BlowPower',None,0,100,None,{'addParameters':'WORK_MODE_H_6','index':'6'}),state.TileConfig(state.TileConfig.TYPE_TEXT,'correctionLambda','ecoSterSetTemp7',0,100,None,{'addParameters':'WORK_MODE_H_7','index':'7'}),state.TileConfig(state.TileConfig.TYPE_TEXT,'pressure','ecoSterSetTemp8',0,100,None,{'addParameters':'WORK_MODE_H_8','index':'8'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts1_b3b4','ecoSterSetTemp1',0,100,None,{'addParameters':'WORK_MODE_H_1','index':'1'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts2_b3b4','ecoSterSetTemp2',0,100,None,{'addParameters':'WORK_MODE_H_2','index':'2'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts3_b3b4','ecoSterSetTemp3',0,100,None,{'addParameters':'WORK_MODE_H_3','index':'3'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts4_b3b4','ecoSterSetTemp4',0,100,None,{'addParameters':'WORK_MODE_H_4','index':'4'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts5_b3b4','ecoSterSetTemp5',0,100,None,{'addParameters':'WORK_MODE_H_5','index':'5'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts6_b3b4','ecoSterSetTemp6',0,100,None,{'addParameters':'WORK_MODE_H_6','index':'6'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts7_b3b4','ecoSterSetTemp7',0,100,None,{'addParameters':'WORK_MODE_H_7','index':'7'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts8_b3b4','ecoSterSetTemp8',0,100,None,{'addParameters':'WORK_MODE_H_8','index':'8'}),state.TileConfig(state.TileConfig.TYPE_NONE,'none1'),state.TileConfig(state.TileConfig.TYPE_NONE,'none2'),state.TileConfig(state.TileConfig.TYPE_NONE,'none3'),state.TileConfig(state.TileConfig.TYPE_NONE,'none4'),state.TileConfig(state.TileConfig.TYPE_NONE,'none5'),state.TileConfig(state.TileConfig.TYPE_NONE,'none6'),state.TileConfig(state.TileConfig.TYPE_NONE,'none7'),state.TileConfig(state.TileConfig.TYPE_NONE,'none8'),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts1_b3b4','mixerSetTemp1',0,100,None,{'addParameters':'WORK_MODE_H_1','index':'1'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts2_b3b4','mixerSetTemp2',0,100,None,{'addParameters':'WORK_MODE_H_2','index':'2'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts3_b3b4','mixerSetTemp3',0,100,None,{'addParameters':'WORK_MODE_H_3','index':'3'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts4_b3b4','mixerSetTemp4',0,100,None,{'addParameters':'WORK_MODE_H_4','index':'4'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts5_b3b4','mixerSetTemp5',0,100,None,{'addParameters':'WORK_MODE_H_5','index':'5'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts6_b3b4','mixerSetTemp6',0,100,None,{'addParameters':'WORK_MODE_H_6','index':'6'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts7_b3b4','mixerSetTemp7',0,100,None,{'addParameters':'WORK_MODE_H_7','index':'7'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts8_b3b4','mixerSetTemp8',0,100,None,{'addParameters':'WORK_MODE_H_8','index':'8'})],ECOMAX850i:[state.TileConfig(state.TileConfig.TYPE_TEMP,'tempCO','tempCOSet',0,100,10),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempFeeder',None,0,100),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempFlueGas',None,0,450,8),state.TileConfig(state.TileConfig.TYPE_TEMP,'tempCWU','tempCWUSet',0,100,12),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempExternalSensor',None,-35,40,13),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempBack',None,0,100,11),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempUpperBuffer',None,0,100,14),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempLowerBuffer',None,0,100,15),state.TileConfig(state.TileConfig.TYPE_TEMP_WAVE,'ecoSterTemp1','ecoSterSetTemp1',0,100,None,{'tempSelection':'ecoSterContacts1','addParameters':'STER_MODE_1;WORK_MODE_H_1','index':'1'}),state.TileConfig(state.TileConfig.TYPE_TEMP_WAVE,'ecoSterTemp2','ecoSterSetTemp2',0,100,None,{'tempSelection':'ecoSterContacts2','addParameters':'STER_MODE_2;WORK_MODE_H_2','index':'2'}),state.TileConfig(state.TileConfig.TYPE_TEMP_WAVE,'ecoSterTemp3','ecoSterSetTemp3',0,100,None,{'tempSelection':'ecoSterContacts3','addParameters':'STER_MODE_3;WORK_MODE_H_3','index':'3'}),state.TileConfig(state.TileConfig.TYPE_TEMP_WAVE,'ecoSterTemp4','ecoSterSetTemp4',0,100,None,{'tempSelection':'ecoSterContacts4','addParameters':'STER_MODE_4;WORK_MODE_H_4','index':'4'}),state.TileConfig(state.TileConfig.TYPE_TEMP_WAVE,'ecoSterTemp5','ecoSterSetTemp5',0,100,None,{'tempSelection':'ecoSterContacts5','addParameters':'STER_MODE_5;WORK_MODE_H_5','index':'5'}),state.TileConfig(state.TileConfig.TYPE_TEMP_WAVE,'ecoSterTemp6','ecoSterSetTemp6',0,100,None,{'tempSelection':'ecoSterContacts6','addParameters':'STER_MODE_6;WORK_MODE_H_6','index':'6'}),state.TileConfig(state.TileConfig.TYPE_TEMP_WAVE,'ecoSterTemp7','ecoSterSetTemp7',0,100,None,{'tempSelection':'ecoSterContacts7','addParameters':'STER_MODE_7;WORK_MODE_H_7','index':'7'}),state.TileConfig(state.TileConfig.TYPE_TEMP_WAVE,'ecoSterTemp8','ecoSterSetTemp8',0,100,None,{'tempSelection':'ecoSterContacts8','addParameters':'STER_MODE_8;WORK_MODE_H_8','index':'8'}),state.TileConfig(state.TileConfig.TYPE_TEMP,'mixerTemp1','mixerSetTemp1',0,100,16),state.TileConfig(state.TileConfig.TYPE_TEMP,'mixerTemp2','mixerSetTemp2',0,100,17),state.TileConfig(state.TileConfig.TYPE_TEMP,'mixerTemp3','mixerSetTemp3',0,100,18),state.TileConfig(state.TileConfig.TYPE_TEMP,'mixerTemp4','mixerSetTemp4',0,100,19),state.TileConfig(state.TileConfig.TYPE_TEMP,'mixerTemp5','mixerSetTemp5',0,100,20),state.TileConfig(state.TileConfig.TYPE_TEMP,'mixerTemp6','mixerSetTemp6',0,100,21),state.TileConfig(state.TileConfig.TYPE_TEMP,'mixerTemp7','mixerSetTemp7',0,100,22),state.TileConfig(state.TileConfig.TYPE_TEMP,'mixerTemp8','mixerSetTemp8',0,100,23),state.TileConfig(state.TileConfig.TYPE_FLAME,'tempOpticalSensor',None,0,100,7),state.TileConfig(state.TileConfig.TYPE_TEXT_ICON,'lambdaLevel',None,0,100,9),state.TileConfig(state.TileConfig.TYPE_LEVEL,'fuelLevel',None,0,100,4),state.TileConfig(state.TileConfig.TYPE_STREAM,'fuelStream',None,0,100,5),state.TileConfig(state.TileConfig.TYPE_POWER,'boilerPower',None,0,100,3),state.TileConfig(state.TileConfig.TYPE_FAN,'fanPower',None,0,100,6),state.TileConfig(state.TileConfig.TYPE_FAN,'fanPowerExhaust',None,0,100),state.TileConfig(state.TileConfig.TYPE_TEXT,'mode',None,0,100,1,state.CANNOT_CONTROL_BOILER),state.TileConfig(state.TileConfig.TYPE_NONE,'none1'),state.TileConfig(state.TileConfig.TYPE_NONE,'none2'),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempUpperSolar',None,0,100,24),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempLowerSolar',None,0,100,25),state.TileConfig(state.TileConfig.TYPE_TEMP_RO,'tempFireplace',None,0,100,26),state.TileConfig(state.TileConfig.TYPE_NONE,'fuelCons'),state.TileConfig(state.TileConfig.TYPE_TEXT,'totalGain',None,0,None,2),state.TileConfig(state.TileConfig.TYPE_NONE,'none5'),state.TileConfig(state.TileConfig.TYPE_B2,'mixerTemp1_b2','ecoSterSetTemp1',0,100,None,{'addParameters':'WORK_MODE_H_1','index':'1'}),state.TileConfig(state.TileConfig.TYPE_B2,'mixerTemp2_b2','ecoSterSetTemp2',0,100,None,{'addParameters':'WORK_MODE_H_2','index':'2'}),state.TileConfig(state.TileConfig.TYPE_B2,'mixerTemp3_b2','ecoSterSetTemp3',0,100,None,{'addParameters':'WORK_MODE_H_3','index':'3'}),state.TileConfig(state.TileConfig.TYPE_B2,'mixerTemp4_b2','ecoSterSetTemp4',0,100,None,{'addParameters':'WORK_MODE_H_4','index':'4'}),state.TileConfig(state.TileConfig.TYPE_B2,'mixerTemp5_b2','ecoSterSetTemp5',0,100,None,{'addParameters':'WORK_MODE_H_5','index':'5'}),state.TileConfig(state.TileConfig.TYPE_B2,'mixerTemp6_b2','ecoSterSetTemp6',0,100,None,{'addParameters':'WORK_MODE_H_6','index':'6'}),state.TileConfig(state.TileConfig.TYPE_B2,'mixerTemp7_b2','ecoSterSetTemp7',0,100,None,{'addParameters':'WORK_MODE_H_7','index':'7'}),state.TileConfig(state.TileConfig.TYPE_B2,'mixerTemp8_b2','ecoSterSetTemp8',0,100,None,{'addParameters':'WORK_MODE_H_8','index':'8'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts1_b3b4','ecoSterSetTemp1',0,100,None,{'addParameters':'WORK_MODE_H_1','index':'1'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts2_b3b4','ecoSterSetTemp2',0,100,None,{'addParameters':'WORK_MODE_H_2','index':'2'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts3_b3b4','ecoSterSetTemp3',0,100,None,{'addParameters':'WORK_MODE_H_3','index':'3'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts4_b3b4','ecoSterSetTemp4',0,100,None,{'addParameters':'WORK_MODE_H_4','index':'4'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts5_b3b4','ecoSterSetTemp5',0,100,None,{'addParameters':'WORK_MODE_H_5','index':'5'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts6_b3b4','ecoSterSetTemp6',0,100,None,{'addParameters':'WORK_MODE_H_6','index':'6'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts7_b3b4','ecoSterSetTemp7',0,100,None,{'addParameters':'WORK_MODE_H_7','index':'7'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts8_b3b4','ecoSterSetTemp8',0,100,None,{'addParameters':'WORK_MODE_H_8','index':'8'}),state.TileConfig(state.TileConfig.TYPE_NONE,'none1'),state.TileConfig(state.TileConfig.TYPE_NONE,'none2'),state.TileConfig(state.TileConfig.TYPE_NONE,'none3'),state.TileConfig(state.TileConfig.TYPE_NONE,'none4'),state.TileConfig(state.TileConfig.TYPE_NONE,'none5'),state.TileConfig(state.TileConfig.TYPE_NONE,'none6'),state.TileConfig(state.TileConfig.TYPE_NONE,'none7'),state.TileConfig(state.TileConfig.TYPE_NONE,'none8'),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts1_b3b4','mixerSetTemp1',0,100,None,{'addParameters':'WORK_MODE_H_1','index':'1'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts2_b3b4','mixerSetTemp2',0,100,None,{'addParameters':'WORK_MODE_H_2','index':'2'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts3_b3b4','mixerSetTemp3',0,100,None,{'addParameters':'WORK_MODE_H_3','index':'3'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts4_b3b4','mixerSetTemp4',0,100,None,{'addParameters':'WORK_MODE_H_4','index':'4'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts5_b3b4','mixerSetTemp5',0,100,None,{'addParameters':'WORK_MODE_H_5','index':'5'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts6_b3b4','mixerSetTemp6',0,100,None,{'addParameters':'WORK_MODE_H_6','index':'6'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts7_b3b4','mixerSetTemp7',0,100,None,{'addParameters':'WORK_MODE_H_7','index':'7'}),state.TileConfig(state.TileConfig.TYPE_B3B4,'ecoSterContacts8_b3b4','mixerSetTemp8',0,100,None,{'addParameters':'WORK_MODE_H_8','index':'8'})]}
PANEL_TILES_FIRST_INDEX=8
CIRCUIT_TILES_FIRST_INDEX=16
B2_TILES_FIRST_INDEX=40
B3_TILES_FIRST_INDEX=48
B4_TILES_FIRST_INDEX=64
CIRCUIT_NAMES=0
PANEL_NAMES=1
STER_NAMES=2
PANEL_CIRCUIT_MAX_NUMBER=8
DEF_ALARMS_NUMBER=100
def crc(message):
result=0
for i in message:
result=result^ord(i)
return chr(result&0xFF)
UID_BASE=32
UID_BASE_BITS=5
CHAR_BITS=8
ECOSTER_THERMOSTATS_SCHEDULE="ecosterThermostats"
ECOMAX_SCHEDULES="ecomaxSchedules"
def tryUTF8(name):
try:
name.decode('utf-8')
return True
except UnicodeError:
return False
def bit5toChar(i):
if i<0 or i>=UID_BASE:
return '#'
if i<10:
return chr(ord('0')+i)
c=chr(ord('A')+i-10)
if c=='O':
c='Z'
return c
def uidStamp(message):
_crc=0xA3A3
for m in message:
b=ord(m)
_crc=_crc^b
for i in range(8):
if _crc&1:
_crc=(_crc>>1)^0xA001
else:
_crc=(_crc>>1)
return chr(_crc%256)+chr((_crc/256)%256)
def msgToUidStr(uid):
message=uid+uidStamp(uid)
bits_in_message=len(message)*CHAR_BITS
len_out=bits_in_message/UID_BASE_BITS
if bits_in_message%UID_BASE_BITS:
len_out+=1
out=[]
conv_int=0
conv_size=0
j=0
for i in range(len_out):
if conv_size<UID_BASE_BITS and j<len(message):
conv_int+=(ord(message[j])<<conv_size)
conv_size+=CHAR_BITS
j+=1
letter_code=conv_int%UID_BASE
conv_int/=UID_BASE
conv_size-=UID_BASE_BITS
out.insert(0,bit5toChar(letter_code))
return "".join(out)
def alarmTimeDecode(_time):
SEC_IN_MIN=60
SEC_IN_HOUR=SEC_IN_MIN*60
SEC_IN_DAY=SEC_IN_HOUR*24
SEC_IN_MONTH=SEC_IN_DAY*31
SEC_IN_YEAR=SEC_IN_MONTH*12
year=_time/SEC_IN_YEAR
_time-=(year*SEC_IN_YEAR)
month=_time/SEC_IN_MONTH
_time-=(month*SEC_IN_MONTH)
day=_time/SEC_IN_DAY
_time-=(day*SEC_IN_DAY)
hour=_time/SEC_IN_HOUR
_time-=(hour*SEC_IN_HOUR)
minute=_time/SEC_IN_MIN
_time-=(minute*SEC_IN_MIN)
sec=_time
year+=2000
month+=1
day+=1
alarmDate=None
try:
alarmDate=datetime.datetime(year=year,month=month,day=day,hour=hour,minute=minute,second=sec)
except:
alarmDate=datetime.datetime.fromtimestamp(0)
return alarmDate
def parseIP(ip):
br=(ip.split('.')if not ip is None else[0,0,0,0])
if len(br)!=4:
raise utils.IPError("Wrong IP bytes number!")
result=''
for n in br:
n=int(n)
if n<0 or n>255:
raise utils.IPError("Wrong byte value, out of range [0,255]!")
result+=chr(n)
return result
def createEcoNetFrame(dest_addr,frame_body):
frame_len=len(frame_body)+9
d=BEGIN_FRAME+chr(frame_len%256)+chr(frame_len/256)+dest_addr+SENDER_ADDR_ECONET+SENDER_TYPE_ECONET+ECONET_VERSION+frame_body
return d+crc(d)+END_FRAME
def createBootloaderFrame(frame_body,device_id='\x68'):
frame_len=len(frame_body)+9
if isinstance(device_id,int):
if device_id==0 or device_id>255:
device_id='\xff'
else:
device_id=chr(device_id-1)
d=BEGIN_FRAME+chr(frame_len%256)+chr(frame_len/256)+'\xED\xFF'+device_id+'\x0A'+frame_body
return d+crc(d)+END_FRAME
def createB0Answer(destAddress,sendConnStat=None):
s=state.getNetwork()
encryptNo=state.ENCRYPTION_NUMBER[s['WIFI_ENCRYPTION']]
ethIP=s['ETH_IP']
ethNetmask=s['ETH_MASK']
ethGateway=s['ETH_GATEWAY']
wlanIP=s['WIFI_IP']
wlanNetmask=s['WIFI_MASK']
wlanGateway=s['WIFI_GATEWAY']
wifiQuality=s['WIFI_QUALITY']
wifiSSID=s['WIFI_SSID']
if isinstance(wifiSSID,unicode):
wifiSSID=wifiSSID.encode('utf-8')
frame_body=FRAME_DEVICE_AVAILABLE+chr(0x01)
frame_body+=parseIP(ethIP)+parseIP(ethNetmask)+ parseIP(ethGateway)+chr(s['ETH_STATUS'])+parseIP(wlanIP)+parseIP(wlanNetmask)+parseIP(wlanGateway)+chr(s['ECOSRV_STATUS'])+chr(encryptNo)+chr(wifiQuality)+chr(s['WIFI_STATUS'])+chr(0)*4+chr(len(wifiSSID))+wifiSSID
return createEcoNetFrame(destAddress,frame_body)
def createReadParamsMsg(destAddress,paramsNo=0xff,index=0x0,frameType=FRAME_GET_PARAMS):
d=frameType+chr(paramsNo)+chr(index)
frame=createEcoNetFrame(destAddress,d)
return frame
def createGetEmSchedules(destAdress,frameType=FRAME_GET_ECOSTER_SCHEDULES):
d=frameType
return createEcoNetFrame(destAdress,d)
def createWifiConfirmationMsg():
d=FRAME_SET_WIFI_ANS
return createEcoNetFrame(SENDER_ADDR_BROADCAST,d)
def programVersionFrame(sender):
struct_tag='\xFF'+'\xFF'
struct_version='\x05'
device_id='\x7A'+'\x00'
processor_signature='\x00'+'\x00'+'\x00'
version=str(state.getSoftVersion()).split(".")
HW_version=chr(int(version[0])%256)+chr(int(version[0])/256)
SW_version=chr(int(version[1])%256)+chr(int(version[1])/256)
BW_version=chr(int(version[2])%256)+chr(int(version[2])/256)
address='\x56'
d=FRAME_PROGRAM_VERSION_ANS+struct_tag+struct_version+device_id+processor_signature+HW_version+SW_version+BW_version+address
return createEcoNetFrame(sender,d)
def generateNumberedParams(params,startIndex=0):
new=[]
for i in range(startIndex):
new.append(params[i])
for i in range(1,MAX_NUMBERED_PARAMETERS_SETS+1):
for j in params[startIndex:]:
new.append(j+'_'+str(i))
return tuple(new)
def generateNumberedDict(dictionary):
new=dict()
for i in range(1,MAX_NUMBERED_PARAMETERS_SETS+1):
for k,v in dictionary.items():
newK=k+'_'+str(i)
new[newK]=v
return new
MAX_NUMBERED_PARAMETERS_SETS=8
PARAMS_TABLE_VERSION='\x00'
PARAMS_TABLE_VERSION_INDEX=0
FIRST_PARAM_INDEX=1
PARAMS_NO_INDEX=2
PARAMS_SHIFT=3
DEF_PARAM_SIZE=1
EDITABLE_PARAMS=('AIRFLOW_POWER_100','AIRFLOW_POWER_50','AIRFLOW_POWER_30','POWER_100','POWER_50','POWER_30','MAX_FAN_BOILER_POWER','MIN_FAN_BOILER_POWER','FUEL_FEEDING_TIME_100','FUEL_FEEDING_TIME_50','FUEL_FEEDING_TIME_30','FUEL_FEEDING_BREAK_100','FUEL_FEEDING_BREAK_50','FUEL_FEEDING_BREAK_30','CYCLE_TIME','H2_HYSTERESIS','H1_HYSTERESIS','BOILER_HYSTERESIS','CONTROL_MODE','MIN_FL_POWER','MAX_FL_POWER','MIN_BOILER_POWER','MAX_BOILER_POWER','MIN_FAN_POWER','MAX_FAN_POWER','T_REDUCTION_AIRFLOW','FAN_POWER_GAIN','FUEL_FLOW_CORRECTION_FL','FUEL_FLOW_CORRECTION','AIRFLOW_CORRECTION_100','FEEDER_CORRECTION_100','AIRFLOW_CORRECTION_50','FEEDER_CORRECTION_50','AIRFLOW_CORRECTION_30','FEEDER_CORRECTION_30','AIRFLOW_POWER_GRATE','HIST_BOILER_GRATE','SUPERVISION_WORK_AIRFLOW','SUPERVISION_WORK_AIRFLOW_BRAKE','CO_TEMP_GRATE','DET_TIME_FUEL_GRATE','AIRFLOW_POWER_KINDLE','SMALL_AIRFLOW_POWER_KINDLE','AIRFLOW_KINDLE_DELAY','SCAVENGE_KINDLE','FEEDER_KINDLE','FEEDER_KINDLE_WEIGHT','KINDLE_TIME','WARMING_UP_TIME','FUMES_TEMP_KINDLE_FINISH','FINISH_KINDLE_THRESHOLD','FUMES_DELTA_KINDLE','DELTA_T_KINDLE','MIN_KINDLE_POWER_TIME','SCAVENGE_AFTER_KINDLE','AIRFLOW_POWER_AFTER_KINDLE','SUPERVISION_TIME','FEED_TIME_SUPERVISION','FEED_TIME_SUPERVISION_WEIGHT','FEED_SUPERVISION_BREAK','SUPERVISON_CYCLE_DURATION','AIRFLOW_POWER_SUPERVISION','FAN_SUPERVISON_BREAK','FAN_WORK_SUPERVISION','INCREASE_FAN_SUPPORT_MODE','MAX_EXTINGUISH_TIME','MIN_EXTINGUISH_TIME','EXTINGUISH_TIME','AIRFLOW_POWER_EXTINGUISH','AIRFLOW_WORK_EXTINGUISH','AIRFLOW_BRAKE_EXTINGUISH','SCAVENGE_START_EXTINGUISH','SCAVENGE_STOP_EXTINGUISH','CLEAN_BEGIN_TIME','EXTINGUISH_CLEAN_TIME','AIRFLOW_POWER_CLEAN','WARMING_UP_BRAKE_TIME','WARMING_UP_CYCLE_TIME','REMIND_TIME','LAMBDA_WORK','LAMBDA_CORRECTION_RANGE','OXYGEN_100','OXYGEN_50','OXYGEN_30','OXYGEN_CORRECTION_FL','FUEL_KG_H','FEEDER_CALIBRATION','FUEL_FACTOR','CALORIFIC_KWH_KG','FUEL_DETECTION_TIME','FUMES_TEMP_FUEL_DETECTION','SCHEDULE_FEEDER_2','FEED2_H1','FEED2_H2','FEED2_H3','FEED2_H4','FEED2_WORK','FEED2_BREAK','CO_TEMP_SET','MIN_SET_CO_TEMP','MAX_SET_CO_TEMP','SWITCH_CO_TEMP','PAUSE_CO_CWU','PAUSE_TERM','WORK_TERM','INCREASE_TEMP_CO','PROGRAM_CONTROL_CO','CO_HEAT_CURVE','PARALLEL_CO_HEAT_CURVE','WEATHER_FACTOR','TERM_BOILER_OPERATION','TERM_BOILER_MODE','DECREASE_SET_CO_TERM','TERM_PUMP_OFF','AL_BOILER_TEMP','MAX_FEED_TEMP','EXTERN_BOILER_TEMP','ALARM_NOTIF','PUMP_HYSTERESIS','CWU_SET_TEMP','MIN_CWU_SET_TEMP','MAX_CWU_SET_TEMP','CWU_WORK_MODE','CWU_HYSTERESIS','CWU_DISINFECTION','AUTO_SUMMER','SUMMER_TEMP_ON','SUMMER_TEMP_OFF','CWU_FEEDING_EXTENSION','CIRCULATION_CONTROL','CIRCULATION_PAUSE_TIME','CIRCULATION_WORK_TIME','CIRCULATION_START_TEMP','BUFFER_CONTROL','BUFFER_MAX_TEMP','MIN_BUFFER_TEMP','BUFFER_HISTERESIS','BUFFER_LOAD_START','BUFFER_LOAD_STOP')
MIXERS_PARAMS=('MIX_SET_TEMP','MIN_MIX_SET_TEMP','MAX_MIX_SET_TEMP','LOW_MIX_SET_TEMP','CTRL_WEATHER_MIX','MIX_HEAT_CURVE','PARALLEL_OFFSET_HEAT_CURV','WEATHER_TEMP_FACTOR','MIX_OPERATION','MIX_INSENSITIVITY','MIX_THERM_OPERATION','MIX_THERM_MODE','MIX_OFF_THERM_PUMP','MIX_SUMMER_WORK')
MIXERS_PARAMS=generateNumberedParams(MIXERS_PARAMS)
ECOSTER_PARAMS=('STER_PROFIL','STER_MODE','STER_TEMP_SET_PARTY','STER_TEMP_SET_SUMMER','STER_CORRECTION','STER_TIMER_EXIT','STER_TIMER_VENT','STER_TIMER_PARTY','STER_TIMER_HOLIDAY','STER_HYSTEREZE','STER_TEMP_DAY','STER_TEMP_NIGHT','STER_TEMP_ANTIFREEZ','STER_TEMP_HEAT','STER_TIMER_HEAT','STER_TIMER_OFF')
ECOSTER_PARAMS_LEN=len(ECOSTER_PARAMS)-1
ECOSTER_PARAMS=generateNumberedParams(ECOSTER_PARAMS,1)
GLOB_ECOSTER_PARAMS_ACTUAL=None
INSTALLATION_PARAMS=('CWU_SET_TEMP','CWU_PRIORITY','CWU_HANDLING','MIN_TEMP_CWU','MAX_TEMP_CWU','CWU_FEEDING_EXTENSION','CWU_HYSTERESIS','CWU_DISINFECTION','CWU_WORK_MODE','SOLAR_HANDLING','SOLAR_DELTA_T_ON','SOLAR_DELTA_T_OFF','MIN_T_COLLECTOR','MAX_T_COLLECTOR','TEMP_OFF_COLLECTOR','MIN_ROT_SOLAR','SOLAR_ANTIFREEZ','CIRCULATION_CONTROL','CIRCULATION_PAUSE_TIME','CIRCULATION_WORK_TIME','CIRCULATION_START_TEMP','MAIN_HEAT_SOURCE','MIN_TEMP_MHS','MAX_TEMP_MHS','HIST_MHS','T_COOLING_MHS','INCREASING_ST_MHS','ADDITIONAL_MHS','T_OFF_MHS','T_STARTU_PUMP_AHS','SCHEMA_HYDR','ANTIFREEZ','ANTIFREEZ_DELAY','CIRCUIT_LOCK_TIME','CIRCUIT_WORK_TIME','ALARM_OUT_C','ALARM_ON_OUT_C','HIST_RT','T_COOLING_ASH','T_LOCK_PUMP_ANNEALING','SUMMER_MODE','TEMP_ON_SUMMER','TEMP_OFF_SUMMER')
INSTALLATION_CIRCUITS=('WORK_MODE_H','SET_TEMP_H','DAY_TEMP_H','NIGHT_TEMP_H','MIN_TEMP_H','MAX_TEMP_H','SUMMER_WORK_H','REGULATION_H','HANDLING_H','THERM_CHOICE_H','DECREASE_THERM_TEMP_H','CORRECTION_THERM_H','LOCK_THERM_H','OPEN_TIME_H','THRESHOLD_H','K_PID_H','TI_PID_H','HEAT_CURVE_H','PARALLEL_HEAT_CURVE_H','FUNCTION_TR_H','NIGHT_LOWER_WATER_H')
INSTALLATION_CIRCUITS=generateNumberedParams(INSTALLATION_CIRCUITS)
MANY_BYTES_PARAMS={'STER_TEMP_SET_PARTY':2,'STER_TEMP_SET_SUMMER':2,'STER_TEMP_DAY':2,'STER_TEMP_NIGHT':2,'STER_TEMP_ANTIFREEZ':2,'STER_TEMP_HEAT':2}
MANY_BYTES_PARAMS=generateNumberedDict(MANY_BYTES_PARAMS)
REG_EDITABLE_PARAMS={ECOMAX850P:EDITABLE_PARAMS,ECOMAX850i:INSTALLATION_PARAMS}
REG_MIXERS_PARAMS={ECOMAX850P:MIXERS_PARAMS,ECOMAX850i:INSTALLATION_CIRCUITS}
BOILER_CONTROL_PARAM='BOILER_CONTROL'
SCHEMA_ID_BYTE_NUMBER=8
def createSetEmSchedulesMsg(destAddress,schedules,frame):
d=frame+schedules
return createEcoNetFrame(destAddress,d)
def createSetParamMsg(destAddress,name,newValue,frame,params,params_no=None):
if params_no is None:
d=frame+chr(params.index(name))+newValue
else:
x=params.index(name)
if x>0:
k,rem=divmod(x-1,ECOSTER_PARAMS_LEN)
x=k*params_no+rem+1
d=frame+chr(x)+newValue
return createEcoNetFrame(destAddress,d)
def createSetMixerParamMsg(destAddress,par,name,newValue,mixerParamsNo,frame,params):
index=params.index(name)
mixerNo=index/mixerParamsNo
paramNo=index%mixerParamsNo
d=frame+chr(mixerNo)+chr(paramNo)+newValue
return createEcoNetFrame(destAddress,d)
def createBoilerControlMsg(destAddress,value):
if value not in[0,1]:
logger.warning("Value out of range for boiler control setting.")
return ''
return createEcoNetFrame(destAddress,FRAME_SET_BOILER_CONTOL+chr(value))
def serveGetAlarms(sender,request):
if hasattr(request,'idxFirst')and hasattr(request,'numAlarms'):
ans=FRAME_GET_ALARMS+chr(request.idxFirst)+chr(request.numAlarms)
else:
logger.error("serveGetAlarms, bad request, no idxFirst or numAlarms member")
ans=FRAME_GET_ALARMS+'\x00'+'\x01'
return createEcoNetFrame(sender,ans)
def convertToDisplay(par):
if par.unit==param.ENUM_UNIT:
return
if par.offset!=0 or par.mult!=1:
par.value=round((par.value-par.offset)*par.mult,param.DEF_PRECISION)
par.minv=round((par.minv-par.offset)*par.mult,param.DEF_PRECISION)
par.maxv=round((par.maxv-par.offset)*par.mult,param.DEF_PRECISION)
def computeParamOffValue(par):
par.offvalue=0
if par.offset!=0 or par.mult!=1:
par.offvalue=round((0-par.offset)*par.mult,param.DEF_PRECISION)
def convertToDisplayRM(par):
if par.unit==param.ENUM_UNIT:
par.value=par.orgvalue
par.minv=par.orgminv
par.maxv=par.orgmaxv
return
if par.offset!=0 or par.mult!=1:
par.value=round((par.orgvalue-par.offset)*par.mult,param.DEF_PRECISION)
par.minv=round((par.orgminv-par.offset)*par.mult,param.DEF_PRECISION)
par.maxv=round((par.orgmaxv-par.offset)*par.mult,param.DEF_PRECISION)
else:
par.value=par.orgvalue
par.minv=par.orgminv
par.maxv=par.orgmaxv
def isNaN(num):
return num!=num
def convertToRegulator(value,par):
if par.unit==param.ENUM_UNIT:
return value
if par.mult==0:
logger.warning("convertToRegulator(): multiply is zero, cannot divide by zero! Returning "+str(value))
return value
if par.offset!=0 or par.mult!=1:
return int(round(value/par.mult+par.offset))
return value
def parseFloat(data):
if data=='\xFF\xFF\xFF\xFF':
return None
result=struct.unpack('<f',data)[0]
if isNaN(result):
return None
return result
def parseInt(data):
if data=='\xFF':
return None
return ord(data)
PARAMS_PARSE_FUNCTION={1:lambda x:ord(x[0]),2:utils.decodeValUShort}
PARAMS_CODE_FUNCTION={1:chr,2:utils.codeValUShortChr}
MODULES_DICT=[["lbModuleAVerCurr",'\x45'],["lbModuleBVerCurr",'\x52'],["lbModuleCVerCurr",'\x53'],["lbLambdaModuleVerCurr",'\x04'],["lbPanelModuleVerCurr",'\x50'],["lbEcoSTERModuleVer1Curr",'\x51'],["lbEcoSTERModuleVer2Curr",'\x57'],["lbEcoSTERModuleVer3Curr",'\x58'],["lbPanel1ModuleVerCurr",'\x60'],["lbPanel2ModuleVerCurr",'\x61'],["lbPanel3ModuleVerCurr",'\x62'],["lbPanel4ModuleVerCurr",'\x63'],["lbPanel5ModuleVerCurr",'\x64'],["lbPanel6ModuleVerCurr",'\x65'],["lbPanel7ModuleVerCurr",'\x66'],["lbEcoIsmCurr",'\x59']]
STRUCT_SIZE={0:31,1:31,2:32,3:33,4:32,5:12}
def getModuleLabel(address):
for opt in MODULES_DICT:
if opt[1]==address:
return opt[0]
return None
def getModuleAddress(label):
for opt in MODULES_DICT:
if opt[0]==label:
return opt[1]
return None
def getDeviceConfigRespCmd(cmd):
for cmdel in SET_CONFIG_FRAMES_MAP:
if cmdel[0]==cmd:
return cmdel[1]
return None
def readSoftSignaturev0(data):
result={}
t=struct.unpack('<H',data[0:2])[0]
if t==0xFF or t==0xFFFF:
result["dev_id"]=0
else:
result["dev_id"]=t+1
result["signature"]=[ord(data[2]),ord(data[3]),ord(data[4]),0x00]
result["hw"]=0x71<<24|((ord(data[5])&0xF0)<<12)|(ord(data[5])&0x0F)<<8
result["sw"]=0x30<<24|struct.unpack('<H',data[6:8])[0]
result["bw"]=0x30<<24|struct.unpack('<H',data[8:10])[0]
result["ver_name"]=readModuleVersion(result["hw"],result["sw"])
result["date"]=data[10:30]
return result
def readSoftSignaturev2(data):
result={}
t=struct.unpack('<H',data[0:2])[0]
if t==0xFF or t==0xFFFF:
result["dev_id"]=0
else:
result["dev_id"]=t+1
result["signature"]=[ord(data[2]),ord(data[3]),ord(data[4]),0x00]
if data[6]=='\x00':
result["hw"]=0x71<<24|((ord(data[5])&0xF0)<<12)|(ord(data[5])&0x0F)<<8
else:
result["hw"]=0x72<<24|((ord(data[6])&0xF0)<<12)|(ord(data[6])&0x0F)<<8|ord(data[5])
result["sw"]=0x30<<24|struct.unpack('<H',data[7:9])[0]
result["bw"]=0x30<<24|struct.unpack('<H',data[9:11])[0]
result["ver_name"]=readModuleVersion(result["hw"],result["sw"])
result["date"]=data[11:31]
return result
def readSoftSignaturev3(data):
result={}
t=struct.unpack('<H',data[0:2])[0]
if t==0xFF or t==0xFFFF:
result["dev_id"]=0
else:
result["dev_id"]=t+1
result["signature"]=[ord(data[2]),ord(data[3]),ord(data[4]),ord(data[5])]
if data[7]=='\x00':
result["hw"]=0x71<<24|((ord(data[6])&0xF0)<<12)|(ord(data[6])&0x0F)<<8
else:
result["hw"]=0x72<<24|((ord(data[7])&0xF0)<<12)|(ord(data[7])&0x0F)<<8|ord(data[6])
result["sw"]=0x30<<24|struct.unpack('<H',data[8:10])[0]
result["bw"]=0x30<<24|struct.unpack('<H',data[10:12])[0]
result["ver_name"]=readModuleVersion(result["hw"],result["sw"])
result["date"]=data[12:32]
return result
def readSoftSignaturev5(data):
result={}
t=struct.unpack('<H',data[0:2])[0]
if t==0xFF or t==0xFFFF:
result["dev_id"]=0
else:
result["dev_id"]=t+1
result["signature"]=[ord(data[2]),ord(data[3]),ord(data[4]),0x00]
if data[6]=='\x00':
result["hw"]=0x71<<24|((ord(data[5])&0xF0)<<12)|(ord(data[5])&0x0F)<<8
else:
result["hw"]=0x72<<24|((ord(data[6])&0xF0)<<12)|(ord(data[6])&0x0F)<<8|ord(data[5])
result["sw"]=0x30<<24|struct.unpack('<H',data[7:9])[0]
result["bw"]=0x30<<24|struct.unpack('<H',data[9:11])[0]
result["ver_name"]=readModuleVersion(result["hw"],result["sw"])
return result
STRUCT_PARSE_FUNC={0:readSoftSignaturev0,1:readSoftSignaturev0,2:readSoftSignaturev2,3:readSoftSignaturev3,4:readSoftSignaturev2,5:readSoftSignaturev5,}
def readModuleVersion(hw_version,fw_version):
part1=((fw_version&0xFFFF00)>>8)
part2=-1
if(hw_version>>24)&0xF0==0x10:
part2=((hw_version&0xF0)>>4)*10+(hw_version&0x0F)
elif(hw_version>>24)&0xF0==0x30:
part2=((hw_version&0xFF00)>>8)*10+(hw_version&0x0F)
else:
part2=((hw_version>>16)&0xFF)*10+((hw_version>>8)&0xFF)
part3=(fw_version&0x00FF)
return "%d.%d.%d"%(part1,part2,part3)
def createLangCode(lang='',command=0):
return lang+"_"+str(command)
class EcomaxProtocol():
CYCLE_REQUEST_PERIOD=60
def __init__(self,parent):
self.parent=parent
self.ecosterNumber=0
self.mixerParamsNo=1
self.alarmsTmp=[]
self.dataFramesRcv=dict()
self.dataFramesNew=dict()
self.regType=ECOMAX850P
self.tiles=[]
self.modifyParamRequest=None
self.modifyParamRequestAns=None
self.modifyParamTryCounter=0
self.confirmWifiSettings=False
self.framesNo=0
self.remoteMenuCommandsRcv=dict()
self.remoteMenuCommandsNew=dict()
self.remoteMenuCRC=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
self.remoteMenuDataToSrvCRC=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
self.remoteMenuCommandsNewOrd=[]
self.remoteMenuDefaultLangIndex=0
self.remoteMenuLangIndex=-1
self.remoteMenuCurrReadLangIndex=-1
self.remoteMenuCurrentServerLang=None
self.remoteMenuControllCounter=0
self.dataInterface=None
self.updater=rsu.RegSoftUpdater()
self.masterStopped=False
self.bootLoaderMode=False
self.paramsInitialized=False
self.msgsInitialized=False
self.modulesVersionSend=self.modulesUpdaterVersionSend=self.getConfigVersionDownload=False
self.sendLoaderQuestion=False
self.sendMasterStopQuestion=False
self.moduleAVersionData=None
self.actPvVersion=None
self.updateEndFlag=False
self.lastConfUploadBurnerIndex=-1
self.lastConfUploadBurnerDataSize=0
self.resetConfigDataObj()
self.resetConfigUploadDataObj()
self.initParams()
self.FRAME_METHOD={FRAME_GET_SETTINGS_ANS:self.parseSettings,FRAME_GET_UID_ANS:self.parseUID,FRAME_GET_PASSWD_ANS:self.parseServicePassword,FRAME_SET_WIFI:self.parseWifiParams,FRAME_GET_ALARMS_ANS:self.parseAlarms,FRAME_DATA_ANS:self.parseCurrentData,FRAME_REGDATA_ANS:self.parseRegCurrentData,FRAME_GET_PARAMS_ANS:lambda:self.parseParams(None,False),FRAME_GET_MIXER_PARAMS_ANS:lambda:self.parseParams(None,True),FRAME_GET_ECOSTER_PARAMS_ANS:lambda:self.parseParams(ECOSTER_PARAMS,False,funky=True),FRAME_GET_PARAMS_CONF_ANS:lambda:self.parseParamsConf(None),FRAME_GET_MIXERS_CONF_ANS:lambda:self.parseParamsConf(None,True),FRAME_GET_ECOSTER_CONF_ANS:lambda:self.parseParamsConf(ECOSTER_PARAMS,False,funky=True),FRAME_GET_PARAMS_STRUCT_ANS:lambda:self.parseParamsStruct(None),FRAME_GET_MIXERS_STRUCT_ANS:lambda:self.parseParamsStruct(None,True),FRAME_GET_ECOSTER_STRUCT_ANS:lambda:self.parseParamsStruct(ECOSTER_PARAMS,False,funky=True),FRAME_GET_NAMES_ANS:self.parseNames,FRAME_GET_ECOSTER_SCHEDULES_ANS:self.parseSchedules,FRAME_SET_ECOSTER_SCHEDULES_ANS:self.parseSchedules,FRAME_GET_TIME_ZONESANS:self.parseSchedules,FRAME_GET_CURRPARAMS_ANS:self.parseCurrentParamsEdits,FRAME_GET_CURRPARAMSCONSTR_ANS:self.parseCurrentParamsConstr,FRAME_PROGRAM_VERSION_ANS:self.parseActualModuleVersions,FRAME_GET_CONFIG_SCHEMA_ANS:self.parseSchemaIntegrData}
self.REMOTE_MENU_METHOD={FRAME_REMOTE_MENU_ANS:self.parseRemoteMenu,}
self.REQUEST_SERVE_DICT={queue.Request.SET_PARAM:self.serveSetParam,queue.Request.GET_UID:lambda sender,req:createEcoNetFrame(sender,FRAME_GET_UID),queue.Request.GET_SERVICE_PASSWORD:lambda sender,req:createEcoNetFrame(sender,FRAME_GET_PASSWD),queue.Request.GET_ALARMS:serveGetAlarms,queue.Request.GET_FRAME_DATA:lambda sender,req:createReadParamsMsg(sender,frameType=req.name),queue.Request.GET_ECOSTER_SCHEDULE:lambda sender,req:createGetEmSchedules(destAdress=SENDER_ADDR_ECOSTERS[self.ecosterNumber],frameType=req.name),queue.Request.SET_ECOSTER_SCHEDULE:self.serveSetEcosterSchedule,queue.Request.GET_SCHEDULE:lambda sender,req:createGetEmSchedules(sender,frameType=req.name),queue.Request.SET_SCHEDULE:self.serveSetEcomaxSchedule,queue.Request.GET_REMOTE_MENU:self.serveGetRemoteMenu,queue.Request.GET_CURRENT_PARAMS_EDITS:lambda sender,req:createEcoNetFrame(sender,FRAME_GET_CURRPARAMS),queue.Request.GET_CURRENT_PARAMS_CONSTR:lambda sender,req:createEcoNetFrame(sender,FRAME_GET_CURRPARAMSCONSTR),queue.Request.SET_CURRENT_PARAM:self.serveSetCurrentParam,queue.Request.GET_MODULES_VER:lambda sender,req:createEcoNetFrame(sender,FRAME_PROGRAM_VERSION),queue.Request.STOP_MASTER:lambda sender,req:self.stopMasterFrame(),queue.Request.ENTER_LOADER:lambda sender,req:self.enterLoaderFrame(),queue.Request.SAVE_LAST_PAGE:lambda sender,req:self.savePage(sender),queue.Request.START_MASTER:lambda sender,req:self.startMaster(),queue.Request.LEAVE_LOADER:lambda sender,req:self.leaveLoader(),queue.Request.CHECK_LOADER:lambda sender,req:self.checkBootloader(sender),queue.Request.GET_DEV_CONFIG:self.createEcoNetGetDevConfigFrame,queue.Request.SET_DEV_CONFIG:self.createEcoNetSetDevConfigFrame}
self.ECO_UPDATER_FRAMES={FRAME_PROGRAM_VERSION:programVersionFrame,FRAME_PROGRAM_VERSION_ANS:self.readModulesVersion,}
self.BOOT_LOADER_FRAMES={FRAME_ENTER_LOADER_ANS:self.enterIntoLoaderAns,FRAME_CONFIRM_LOADER_ANS:self.confirmLoaderAns,FRAME_DELETE_SOFTWARE_ANS:self.deleteSoftAns,FRAME_SAVE_FLASH_ANS:self.savePageAns,FRAME_VERIFY_PROGRAM_ANS:self.verifySendedSoftAns,FRAME_SOFT_INCOMPATIBLE:lambda sender:self.catchUpdateException(sender,"Soft incompatible"),FRAME_NO_INIT_DATA_ERROR:lambda sender:self.catchUpdateException(sender,"no init data"),FRAME_AUTOIDENT_DATA_ERROR:lambda sender:self.catchUpdateException(sender,"autoidentyfication data error"),FRAME_KRYPTOGRAPHIC_ERROR:lambda sender:self.catchUpdateException(sender,"kryptographic error"),FRAME_ADDRESS_ERROR:lambda sender:self.catchUpdateException(sender,"address error"),FRAME_DATA_SIZE_ERROR:lambda sender:self.catchUpdateException(sender,"data size error"),FRAME_ERROR_FRAME:lambda sender:self.catchUpdateException(sender,"error frame or reg is not in bootloader"),FRAME_LEAVE_LOADER_ANS:self.leaveLoaderAns,}
self.ECO_CONFIG_IMPORT_EXPORT_FRAMES={FRAME_GET_CONFIG_SCHEMA_ANS:self.readConfigFrameDataSchema,FRAME_GET_CONFIG_CURRENT_EDIT_ANS:self.readConfigFrameDataCurrent,FRAME_GET_CONFIG_COMMON_ANS:self.readConfigFrameDataFabric,FRAME_GET_CONFIG_TEXTS_ANS:self.readConfigFrameDataFabric,FRAME_GET_CONFIG_NOEDIT_ANS:self.readConfigFrameDataFabric,FRAME_GET_CONFIG_BURNERS_ANS:self.readConfigFrameDataFabric,FRAME_GET_CONFIG_BURNERS_NOINDEX_ANS:self.readConfigFrameDataFabric,FRAME_SET_CONFIG_CURRENT_EDIT_ANS:self.writeConfigFrameDataCurrFabric,FRAME_SET_CONFIG_COMMON_VALS_ANS:self.writeConfigFrameDataCurrFabric,FRAME_SET_CONFIG_COMMON_ANS:self.writeConfigFrameDataCurrFabric,FRAME_SET_CONFIG_TEXTS_ANS:self.writeConfigFrameDataCurrFabric,FRAME_SET_CONFIG_NOEDIT_ANS:self.writeConfigFrameDataCurrFabric,FRAME_SET_CONFIG_BURNERS_ANS:self.writeConfigFrameDataCurrFabric,FRAME_SET_CONFIG_EEPROM_CL_ANS:self.writeConfigFrameDataCurrFabric}
def initParams(self):
self.editableParams=dict()
self.rmTabsInit()
self.editableParamsOrigValues=dict()
self.editableParamsDescr=dict()
self.remoteMenuLangsVers=dict()
self.namesParams=dict()
self.modulesVersData=[]
self.modulesVersVerifString=''
self.modulesVersVerifLastDate=0
self.paramsInitialized=True
self.fuelConsum=0
self.fuelStreamTime=time.time()
def addValueToFuelConsum(self,value):
global mutex
with mutex:
self.fuelConsum+=value
def getFuelConsum(self):
global mutex
with mutex:
retFuelCons=self.fuelConsum
self.fuelConsum=0
return retFuelCons
def fcRegType(self):
return self.regType==ECOMAX850P
def resetFuelConsum(self):
global mutex
with mutex:
self.fuelConsum=0
def rmTabsInit(self):
self.currentDataDispParams=dict()
self.currentDataParamsEdits=dict()
self.currentDataParamsConstr=[]
self.currentDataParamsValues=dict()
self.remoteMenuNextCommand=dict()
self.remoteMenuNextCommand['command']=0
self.remoteMenuNextCommand['extra']=None
self.remoteMenuPrevCommand=dict()
self.remoteMenuFramesSend=[]
self.remoteMenuLangs=[]
self.remoteMenuMissingLangs=[]
self.remoteMenuStructure=[]
self.remoteMenuCatsNames=[]
self.remoteMenuParamsNames=[]
self.remoteMenuParamsData=[]
self.remoteMenuParamsUnits=[]
self.remoteMenuParamsEnums=[]
self.remoteMenuParamsDescs=[]
self.remoteMenuCatsDescs=[]
self.remoteMenuLocksNames=[]
self.remoteMenuPasswords=[]
self.remoteMenuAlarmsNames=dict()
self.remoteMenuLangToSrvData=dict()
self.remoteMenuLangsDownloadCounter=dict()
self.remoteMenuLockedLangs=[]
self.remoteMenuSavedSettings=None
self.remoteMenuLangsData=None
self.remoteMenuCurrentServerLang=None
self.remoteMenuEditCycleFlag=False
def getCycleRequestPeriod(self):
return EcomaxProtocol.CYCLE_REQUEST_PERIOD
def setFrame(self,frame):
self.message=frame
def getDeviceIdByLabel(self,label):
for ver in self.modulesVersData:
if len(ver)>2 and ver[0]==label:
if ver[2]<256:
return chr(ver[2])
return '\x68'
def frameAnalyze(self):
if len(self.message)==0:
return None,False
order=self.message[7]
if state.getRegAllowed()or order==FRAME_GET_UID_ANS or order==FRAME_CHECK_DEVICE or order==FRAME_SET_WIFI:
questionFrameInt=ord(order)-128
questionFrame=None
if questionFrameInt>=0:
questionFrame=chr(questionFrameInt)
if not self.updater is None and(self.updater.running or self.updater.configUpdateRunning):
if(self.updater.running or(self.updater.configUpdateRunning and not self.configUploadProcessInProgress))and self.message[3]=='\x55' and order=='\xc0' and order in self.ECO_UPDATER_FRAMES:
return self.ECO_UPDATER_FRAMES[order](self.message[4]),True
if self.updater.running and self.message[3:5]=='\xFF\xED' and(self.bootLoaderMode or self.parent.failedLoaderEnterFlag or(self.sendLoaderQuestion and order==FRAME_ENTER_LOADER_ANS)or order==FRAME_CONFIRM_LOADER_ANS)and order in self.BOOT_LOADER_FRAMES:
return self.BOOT_LOADER_FRAMES[order](self.message[4]),True
if(self.configDownloadProcessInProgress or self.configUploadProcessInProgress)and order in self.ECO_CONFIG_IMPORT_EXPORT_FRAMES and(order==self.configDownloadProcessWaitForCommand[0]or order==self.configUploadActualCommand or(self.configDownloadProcessWaitForCommand[0]==FRAME_GET_CONFIG_BURNERS_ANS and order==FRAME_GET_CONFIG_BURNERS_NOINDEX_ANS)):
return self.ECO_CONFIG_IMPORT_EXPORT_FRAMES[order](self.message[4]),True
if self.message[3]=='\x55' and order=='\xc0' and not questionFrame in self.dataFramesNew:
self.FRAME_METHOD[order]()
return None,False
if (self.message[3]!=SENDER_ADDR_ECONET)and(self.message[3]!=SENDER_ADDR_BROADCAST):
return None,False
if not self.modifyParamRequest is None:
if order==self.modifyParamRequestAns or self.modifyParamTryCounter>=MODIFY_PARAM_ATTEMPTS:
if not self.modifyParamRequest.chgMonitor is None:
self.modifyParamRequest.chgMonitor.set()
if order==self.modifyParamRequestAns:
if self.modifyParamRequest.name!=BOILER_CONTROL_PARAM and type(self.modifyParamRequest.value)==type(self.parent.editableParams[self.modifyParamRequest.name].value):
self.parent.editableParams[self.modifyParamRequest.name].value=self.modifyParamRequest.value
self.parent.setNewEditableParams(self.editableParams)
self.modifyParamRequest=None
self.modifyParamRequestAns=None
self.modifyParamTryCounter=0
return None,False
else:
self.modifyParamTryCounter+=1
return self.getAnswerForRequest(self.modifyParamRequest),True
if order==FRAME_CHECK_DEVICE:
uid=state.getUID()
if((uid is None or(not uid is None and len(uid)==0))and self.parent.queue.getQueueSize()==0):
if not self.paramsInitialized:
self.initParams()
self.initMsgQueue()
if self.confirmWifiSettings:
self.confirmWifiSettings=False
return createWifiConfirmationMsg(),True
else:
return None,True
if order in self.FRAME_METHOD:
self.FRAME_METHOD[order]()
if order==FRAME_SET_WIFI:
self.confirmWifiSettings=True
if not questionFrame is None and questionFrame in self.dataFramesNew:
self.dataFramesRcv[questionFrame]=self.dataFramesNew[questionFrame]
del self.dataFramesNew[questionFrame]
if(order!=FRAME_PROGRAM_VERSION_ANS)and order in self.ECO_UPDATER_FRAMES:
return self.ECO_UPDATER_FRAMES[order](self.message[4]),True
if order in self.REMOTE_MENU_METHOD and not questionFrame is None and(questionFrame in self.dataFramesNew or questionFrame in self.dataFramesRcv):
result=self.REMOTE_MENU_METHOD[order]()
if not result is None:
if not questionFrame is None and questionFrame in self.dataFramesNew:
self.dataFramesRcv[questionFrame]=self.dataFramesNew[questionFrame]
self.remoteMenuEditCycleFlag=False
del self.dataFramesNew[questionFrame]
return None,False
def getReplyDelayTime(self):
return 0
def getAnswerForEmptyQueue(self):
self.actPvVersion=ord(self.message[6])
if not self.updateEndFlag:
if not self.updater is None and self.updater.running:
if self.parent.updateProcessEndFlag:
self.updater.endUpdateError()
self.parent.updateProcessEndFlag=False
self.parent.updateLeaveLoaderCounter=0
else:
if self.updater.module!='\x45' and self.masterStopped and not self.updater.endFileAddress():
if self.updater.updaterReinitRepNum<self.parent.REG_FAILED_REINIT_TOTAL_REP:
self.updater.updaterReinitRepNum+=1
return createEcoNetFrame('\x45',FRAME_STOP_MASTER)
elif self.sendLoaderQuestion:
return self.enterLoaderFrame()
elif self.sendMasterStopQuestion:
if self.updater.updaterStopMasterRepNum<self.parent.REG_STOP_MASTER_TOTAL_REP:
self.updater.updaterStopMasterRepNum+=1
return createEcoNetFrame('\x45',FRAME_STOP_MASTER)
else:
self.parent.updateProcessEndFlag=True
elif self.updater.isUpdateProcessTimeout()or(self.updater.endFileAddress()and self.updater.verified):
self.updater.endUpdateError()
self.parent.updateProcessEndFlag=False
self.parent.updateLeaveLoaderCounter=0
self.updater.updaterReinitRepNum=0
else:
self.parent.updateProcessEndFlag=False
self.masterStopped=False
return createB0Answer(self.message[4],self.message[8])
def getAnswerForRequest(self,request):
sender=self.message[4]
if request.type not in self.REQUEST_SERVE_DICT:
raise queue.UnknownRequest("processMsg(): Unknown request type: "+str(request.type))
return self.REQUEST_SERVE_DICT[request.type](sender,request)
def serveSetEcosterSchedule(self,sender,request):
try:
if request.value==ECOSTER_THERMOSTATS_SCHEDULE:
scheduleData=state.getScheduleByLabel(ECOSTER_THERMOSTATS_SCHEDULE)
key,value=request.extra.popitem()
if len(value)==42:
chanedData=[]
for i in range(len(value)):
if i%6==0:
dayData=[]
dayData.append(value[i])
if((i+1)%6)==0:
chanedData.append(dayData)
scheduleData[key]=chanedData
scheduleFrameData=''
for t in xrange(3):
tmpThermSchedule=scheduleData['ecosterThermSchedule_'+str(t)]
for j in xrange(len(tmpThermSchedule)):
tmpDaySchedule=tmpThermSchedule[j]
for k in xrange(len(tmpDaySchedule)):
scheduleFrameData=scheduleFrameData+chr(tmpDaySchedule[k])
return createSetEmSchedulesMsg(SENDER_ADDR_ECOSTERS[self.ecosterNumber],scheduleFrameData,FRAME_SET_ECOSTER_SCHEDULES)
except:
logger.warning("serveSetEcosterSchedule(): Schedule not send to device!")
def serveSetEcomaxSchedule(self,sender,request):
try:
if request.value==ECOMAX_SCHEDULES:
scheduleData=state.getScheduleByLabel(ECOMAX_SCHEDULES)
key,value=request.extra.popitem()
if len(value)==46:
dataLen=len(value)
chanedData=[]
for i in range(dataLen-4):
if i%6==0:
dayData=[]
dayData.append(value[i])
if((i+1)%6)==0:
chanedData.append(dayData)
scheduleData[key]=chanedData
scheduleFrameData=''
scheduleFrameData+='\x01'
scheduleFrameData+=chr(ECOMAXDATA_TIMEZONES_TYPES.index(key))
scheduleFrameData+=chr(value[dataLen-4])
dval=value[dataLen-3]
if dval<0:
dval=dval+256
scheduleFrameData+=chr(dval)
tmpEcomaxSchedule=scheduleData[key]
for j in xrange(len(tmpEcomaxSchedule)):
tmpDaySchedule=tmpEcomaxSchedule[j]
for k in xrange(len(tmpDaySchedule)):
scheduleFrameData=scheduleFrameData+chr(tmpDaySchedule[k])
if key in ECOSTER_TIMESONES_TYPES:
return createSetEmSchedulesMsg(SENDER_ADDR_ECOSTERS[self.ecosterNumber],scheduleFrameData,FRAME_SET_ECOSTER_SCHEDULES)
else:
return createSetEmSchedulesMsg(sender,scheduleFrameData,FRAME_SET_TIME_ZONES)
except:
logger.warning("serveSetEcomaxSchedule(): Schedule not send to device!")
def serveSetParam(self,sender,request):
if request.name==BOILER_CONTROL_PARAM:
self.modifyParamRequest=request
self.modifyParamRequestAns=FRAME_SET_BOILER_CONTOL_ANS
return createBoilerControlMsg(sender,request.value)
newValue=request.value
par=self.parent.editableParams[request.name]
if not par.isInRange(newValue)and(not request.name in PARAMETERS_WITH_OFF_POSSIBILITY or(request.name in PARAMETERS_WITH_OFF_POSSIBILITY and newValue!=par.offvalue)):
logger.warning("Value out of range for param "+request.name+". Given value: "+str(newValue)+". Range: ["+str(par.minv)+","+str(par.maxv)+"].")
return ''
self.modifyParamRequest=request
if request.name in self.editableParamsDescr:
newValue=convertToRegulator(newValue,self.editableParamsDescr[request.name])
dataLen=1
if request.name in MANY_BYTES_PARAMS:
dataLen=MANY_BYTES_PARAMS[request.name]
newValue=PARAMS_CODE_FUNCTION[dataLen](newValue)
if request.name in ECOSTER_PARAMS:
self.modifyParamRequestAns=FRAME_SET_ECOSTER_PARAM_ANS
return createSetParamMsg(sender,request.name,newValue,FRAME_SET_ECOSTER_PARAM,ECOSTER_PARAMS,params_no=GLOB_ECOSTER_PARAMS_ACTUAL)
elif request.name in REG_EDITABLE_PARAMS[self.regType]:
self.modifyParamRequestAns=FRAME_SET_PARAM_ANS
return createSetParamMsg(sender,request.name,newValue,FRAME_SET_PARAM,REG_EDITABLE_PARAMS[self.regType])
elif request.name in REG_MIXERS_PARAMS[self.regType]:
self.modifyParamRequestAns=FRAME_SET_MIXER_PARAM_ANS
return createSetMixerParamMsg(sender,par,request.name,newValue,self.mixerParamsNo,FRAME_SET_MIXER_PARAM,REG_MIXERS_PARAMS[self.regType])
else:
logger.warning("serveSetParam(): Unknown request name!")
def initMsgQueue(self):
self.dataFramesRcv=dict()
self.remoteMenuCommandsRcv=dict()
self.parent.queue.addGetUID()
self.parent.queue.addGetServicePassword()
self.msgsInitialized=True
def addCyclicReqests(self):
pass
def isParamValid(self,data):
for i in data:
if i!='\xFF':
return True
return False
def addNewVersionRequestToQueue(self,frame,option=0,extra=None,begin=False,force=False):
if frame in IGNORE_FRAMES:
return
if frame==FRAME_GET_ALARMS:
self.parent.queue.addGetAlarms(0,DEF_ALARMS_NUMBER)
elif frame==FRAME_GET_ECOSTER_SCHEDULES:
self.parent.queue.addGetEcosterSchedules(frame)
elif frame==FRAME_GET_TIME_ZONES:
self.parent.queue.addGetEmSchedules(frame)
elif frame==FRAME_REMOTE_MENU:
self.remoteMenuControllCounter=0
self.remoteMenuEditCycleFlag=True
if option==0:
self.remoteMenuCommandsNew=dict()
self.parent.remoteMenuCurrentLangDownlowading=True
if begin:
self.parent.queue.addGetRemoteMenuAtBegining(frame,option,extra)
else:
self.parent.queue.addGetRemoteMenu(frame,option,extra)
self.remoteMenuNextCommand=dict()
self.remoteMenuNextCommand['command']=option
self.remoteMenuNextCommand['extra']=extra
elif frame==FRAME_GET_CURRPARAMS:
self.parent.queue.addGetCurrentParamsEdits()
elif frame==FRAME_GET_CURRPARAMSCONSTR:
self.parent.queue.addGetCurrentParamsConstr()
else:
self.parent.queue.addGetAnyDataFrame(frame)
def setNextCommandDefault(self):
self.remoteMenuNextCommand=dict()
self.remoteMenuNextCommand['command']=0
self.remoteMenuNextCommand['extra']=None
def addNewFrameVersion(self,frame,version):
if frame!=FRAME_REMOTE_MENU or not self.parent.remoteMenuCurrentLangDownlowading and self.remoteMenuCurrentServerLang is None:
self.addNewVersionRequestToQueue(frame)
self.dataFramesNew[frame]=version
else:
if frame==FRAME_REMOTE_MENU:
if self.remoteMenuControllCounter>REMOTE_MENU_REPEAT_IN_PARSECURRENT_COUNT:
self.dataFramesNew={}
self.reloadLang()
else:
self.remoteMenuControllCounter+=1
def parseCurrentData(self):
try:
moduleASoftVer=None
moduleBSoftVer=None
moduleCSoftVer=None
moduleLambdaSoftVer=None
moduleEcoSTERSoftVer=None
modulePanelSoftVer=None
msg=self.message[8:-2]
self.defaultData()
dataFramesNumber=ord(msg[0])
index=1
remote_menu=False
newFramesTable=[]
newFramesHex=[]
for i in range(dataFramesNumber):
frame=msg[index]
newFramesTable.append(frame)
if frame in ECONET_REQUEST_FRAMES_LIST:
if frame in REMOTE_MENU_FRAMES:
remote_menu=True
version=utils.decodeValUShort(msg[index+1:index+3])
newFramesHex.append(utils.toHexString(frame)+" - "+str(version))
if frame in self.dataFramesRcv:
if self.dataFramesRcv[frame]!=version:
self.addNewFrameVersion(frame,version)
else:
if not self.dataFramesNew is None and bool(self.dataFramesNew):
langReload=False
if frame==FRAME_REMOTE_MENU and FRAME_REMOTE_MENU in self.dataFramesNew and self.dataFramesNew[FRAME_REMOTE_MENU]!=version:
langReload=True
self.dataFramesNew={}
if langReload:
self.reloadLang()
elif frame in self.dataFramesNew:
del self.dataFramesNew[frame]
else:
self.addNewFrameVersion(frame,version)
else:
pass
index+=3
if not self.updater is None and self.updater.running:
if self.updater.updateIsAfterVerifiedState()or self.updateEndFlag:
self.bootLoaderMode=False
self.updater.endUpdate(self.actPvVersion)
self.updateEndFlag=False
if FRAME_GET_ECOSTER_PARAMS in self.dataFramesRcv and FRAME_GET_ECOSTER_PARAMS not in newFramesTable:
self.editableParamsDelete(ECOSTER_PARAMS)
del self.dataFramesRcv[FRAME_GET_ECOSTER_PARAMS]
if FRAME_GET_PARAMS in self.dataFramesRcv and FRAME_GET_PARAMS not in newFramesTable:
self.editableParamsDelete(self.chooseParamtersTable(False))
del self.dataFramesRcv[FRAME_GET_PARAMS]
if FRAME_GET_MIXERS_PARAMS in self.dataFramesRcv and FRAME_GET_MIXERS_PARAMS not in newFramesTable:
self.editableParamsDelete(self.chooseParamtersTable(True))
del self.dataFramesRcv[FRAME_GET_MIXERS_PARAMS]
if FRAME_REMOTE_MENU in self.dataFramesRcv and FRAME_REMOTE_MENU not in newFramesTable:
self.rmTabsInit()
self.parent.refreshRemoteMenuData()
for i in range(len(REMOTE_MENU_FRAMES)):
if REMOTE_MENU_FRAMES[i]in self.dataFramesRcv:
del self.dataFramesRcv[REMOTE_MENU_FRAMES[i]]
self.remoteMenuCommandsRcv=dict()
self.parent.remoteMenuCurrentLangDownlowading=False
self.remoteMenuCurrentServerLang=None
if remote_menu:
self.getAndSendRemoteMenuDataToServer()
self.checkRemoteMenuCommandProgress()
if self.configDownloadProcessInProgress and not self.getConfigVersionDownload:
self.resumeConfigDownloadProcess()
if self.configUploadProcessInProgress:
self.resumeConfigUploadProcess()
if(not self.updater is None and(self.updater.running or self.updater.configUpdateRunning or self.configDownloadProcessInProgress))and(self.modulesUpdaterVersionSend or self.getConfigVersionDownload):
self.askForDeviceSoftVer()
state.setRemoteMenuStatus(remote_menu)
self.data.mode=ord(msg[index])
index+=1
outputs=struct.unpack('<I',msg[index:index+4])[0]
self.data.fanWorks=bool(outputs&0x01)
self.data.feederWorks=bool(outputs&0x02)
self.data.pumpCOWorks=bool(outputs&0x04)
self.data.pumpCWUWorks=bool(outputs&0x08)
self.data.pumpCirculationWorks=bool(outputs&0x10)
self.data.lighterWorks=bool(outputs&0x20)
self.data.alarmOutputWorks=bool(outputs&0x40)
self.data.outerBoilerWorks=bool(outputs&0x80)
self.data.fan2ExhaustWorks=bool(outputs&0x100)
self.data.feeder2AdditionalWorks=bool(outputs&0x200)
self.data.feederOuterWorks=bool(outputs&0x400)
self.data.pumpSolarWorks=bool(outputs&0x800)
self.data.pumpFireplaceWorks=bool(outputs&0x1000)
self.data.contactGZCActive=bool(outputs&0x2000)
self.data.blowFan1Active=bool(outputs&0x4000)
self.data.blowFan2Active=bool(outputs&0x8000)
index+=4
outputsFlags=struct.unpack('<I',msg[index:index+4])[0]
self.data.fan=bool(outputs&0x01)
self.data.feeder=bool(outputs&0x02)
self.data.pumpCO=bool(outputsFlags&0x04)
self.data.pumpCWU=bool(outputsFlags&0x08)
self.data.pumpCirculation=bool(outputsFlags&0x10)
self.data.lighter=bool(outputs&0x20)
self.data.alarmOutput=bool(outputs&0x40)
self.data.outerBoiler=bool(outputs&0x80)
self.data.fan2Exhaust=bool(outputs&0x100)
self.data.feeder2Additional=bool(outputs&0x200)
self.data.feederOuter=bool(outputs&0x400)
self.data.pumpSolar=bool(outputsFlags&0x800)
self.data.pumpFireplace=bool(outputs&0x1000)
self.data.contactGZC=bool(outputs&0x2000)
self.data.blowFan1=bool(outputs&0x4000)
self.data.blowFan2=bool(outputs&0x8000)
index+=4
numT=ord(msg[index])
index+=1
for i in range(numT):
tempIndex=ord(msg[index])
raw_data=msg[index+1:index+5]
if raw_data!='\xFF\xFF\xFF\xFF':
t=struct.unpack('<f',raw_data)[0]
if isNaN(t):
t=None
if tempIndex<len(ECOMAXDATA_TEMP_MEMBER_NAMES)and tempIndex>=0:
setattr(self.data,ECOMAXDATA_TEMP_MEMBER_NAMES[tempIndex],t)
else:
logger.error("parseCurrentData: There is no parameter number "+str(tempIndex)+" in ECOMAXDATA_TEMP_MEMBER_NAMES")
index+=5
self.data.tempCOSet=parseInt(msg[index])
self.data.statusCO=parseInt(msg[index+1])
self.data.tempCWUSet=parseInt(msg[index+2])
self.data.statusCWU=parseInt(msg[index+3])
alarmsNo=ord(msg[index+4])
index+=5+alarmsNo
self.data.fuelLevel=parseInt(msg[index])
self.data.transmission=parseInt(msg[index+1])
self.data.fanPower=parseFloat(msg[index+2:index+6])
self.data.boilerPower=parseInt(msg[index+6])
self.data.boilerPowerKW=parseFloat(msg[index+7:index+11])
self.data.fuelStream=parseFloat(msg[index+11:index+15])
if not self.data.fuelStream is None and state.getFuelConsumptionCalc():
currTime=time.time()
diffTime=currTime-self.fuelStreamTime
if diffTime<=300 and diffTime>=0:
try:
fuelCons=self.data.fuelStream*(diffTime/3600)
self.addValueToFuelConsum(fuelCons)
except:
pass
self.fuelStreamTime=currTime
self.data.thermostat=parseInt(msg[index+15])
index+=16
tmp_vers_info=[]
moduleASoftVerTuple=struct.unpack('<BBBBB',msg[index:index+5])
moduleASoftVer=".".join(map(str,moduleASoftVerTuple[:3]))+"."+chr(moduleASoftVerTuple[3])+str(moduleASoftVerTuple[4])
tmp_vers_info.append(str(moduleASoftVer))
index+=5
if ord(msg[index])==0xff:
moduleBSoftVer=None
index+=1
else:
moduleBSoftVer=".".join(map(str,struct.unpack('<BBB',msg[index:index+3])))
index+=3
tmp_vers_info.append(str(moduleBSoftVer))
if ord(msg[index])==0xff:
moduleCSoftVer=None
index+=1
else:
moduleCSoftVer=".".join(map(str,struct.unpack('<BBB',msg[index:index+3])))
index+=3
tmp_vers_info.append(str(moduleCSoftVer))
if ord(msg[index])==0xff:
moduleLambdaSoftVer=None
index+=1
else:
moduleLambdaSoftVer=".".join(map(str,struct.unpack('<BBB',msg[index:index+3])))
index+=3
tmp_vers_info.append(str(moduleLambdaSoftVer))
if ord(msg[index])==0xff:
moduleEcoSTERSoftVer=None
index+=1
else:
moduleEcoSTERSoftVer=".".join(map(str,struct.unpack('<BBB',msg[index:index+3])))
index+=3
tmp_vers_info.append(str(moduleEcoSTERSoftVer))
if ord(msg[index])==0xff:
modulePanelSoftVer=None
index+=1
else:
modulePanelSoftVer=".".join(map(str,struct.unpack('<BBB',msg[index:index+3])))
index+=3
tmp_vers_info.append(str(modulePanelSoftVer))
if ord(msg[index])==0xff:
index+=1
else:
self.data.lambdaStatus=ord(msg[index])
self.data.lambdaSet=ord(msg[index+1])
llevel=struct.unpack('<h',msg[index+2:index+4])[0]
if isNaN(llevel):
llevel=None
self.data.lambdaLevel=llevel
index+=4
if ord(msg[index])==0xff:
index+=1
else:
thermContacts=ord(msg[index])
index+=1
num_therm=ord(msg[index])
tmp_vers_info.append(str(num_therm))
setattr(self.data,'ecoSterNumber',num_therm)
index+=1
if num_therm>0:
mask=1
schedmask=1<<3
for m in range(1,num_therm+1):
setattr(self.data,'ecoSterContacts'+str(m),bool(thermContacts&mask))
setattr(self.data,'ecoSterDaySched'+str(m),bool(thermContacts&schedmask))
setattr(self.data,'ecoSterMode'+str(m),ord(msg[index]))
if ord(msg[index])!=0xff:
self.ecosterNumber=m-1
setattr(self.data,'ecoSterTemp'+str(m),parseFloat(msg[index+1:index+5]))
setattr(self.data,'ecoSterSetTemp'+str(m),parseFloat(msg[index+5:index+9]))
index+=9
mask=mask<<1
schedmask=schedmask<<1
vers_info_string=':'.join(tmp_vers_info)
if vers_info_string!=self.modulesVersVerifString:
self.modulesVersVerifLastDate=0
self.modulesVersVerifString=vers_info_string
ver_time_diff=time.time()-self.modulesVersVerifLastDate
if ver_time_diff>3600:
self.parent.queue.addGetModulesVerIfNotInQueue()
self.modulesVersionSend=True
mixersNbr=ord(msg[index])
index+=1
if mixersNbr>0:
for m in range(1,mixersNbr+1):
setattr(self.data,'mixerTemp'+str(m),parseFloat(msg[index:index+4]))
setattr(self.data,'mixerSetTemp'+str(m),parseInt(msg[index+4]))
mixerOutputs=parseInt(msg[index+6])
setattr(self.data,'mixerPumpWorks'+str(m),bool(mixerOutputs&0x01))
index+=8
state.setModulesVersions(moduleASoftVer,moduleBSoftVer,moduleCSoftVer,moduleLambdaSoftVer,moduleEcoSTERSoftVer,modulePanelSoftVer)
msg_len=len(msg)
if index>=msg_len:
self.parent.data=copy.deepcopy(self.data)
return
for t in self.tiles:
if t.memberName_=="fanPowerExhaust":
setattr(self.data,'fanPowerExhaust',parseFloat(msg[index:index+4]))
index+=4
break
if index>=msg_len:
self.parent.data=copy.deepcopy(self.data)
return
for t in self.tiles:
if t.memberName_=="blowFan1BlowPower":
setattr(self.data,'blowFan1BlowPower',parseFloat(msg[index:index+4]))
index+=4
break
if index>=msg_len:
self.parent.data=copy.deepcopy(self.data)
return
for t in self.tiles:
if t.memberName_=="blowFan2BlowPower":
setattr(self.data,'blowFan2BlowPower',parseFloat(msg[index:index+4]))
index+=4
break
if index>=msg_len:
self.parent.data=copy.deepcopy(self.data)
return
for t in self.tiles:
if t.memberName_=="thermoTemp":
setattr(self.data,'thermoTemp',parseFloat(msg[index:index+4]))
index+=4
break
if index>=msg_len:
self.parent.data=copy.deepcopy(self.data)
return
for t in self.tiles:
if t.memberName_=="thermoSetTemp":
setattr(self.data,'thermoSetTemp',int(parseFloat(msg[index:index+4])))
index+=4
break
if index>=msg_len:
self.parent.data=copy.deepcopy(self.data)
return
for t in self.tiles:
if t.memberName_=="correctionLambda":
setattr(self.data,'correctionLambda',int(parseFloat(msg[index:index+4])))
index+=4
break
if index>=msg_len:
self.parent.data=copy.deepcopy(self.data)
return
for t in self.tiles:
if t.memberName_=="pressure":
setattr(self.data,'pressure',int(parseFloat(msg[index:index+4])))
index+=4
break
self.parent.data=copy.deepcopy(self.data)
except Exception as ex:
logger.error("parseCurrentData(): "+str(ex))
logger.error(traceback.format_exc())
def parseRegCurrentData(self):
msg=self.message[8:-2]
index=2
frame_version=str(ord(msg[index+1]))+"."+str(ord(msg[index]))
index+=2
if frame_version==REGDATA_VERSION:
dataFramesNumber=ord(msg[index])
index+=1
newFramesHex=[]
for i in range(dataFramesNumber):
frame=msg[index]
version=utils.decodeValUShort(msg[index+1:index+3])
newFramesHex.append(utils.toHexString(frame)+" - "+str(version))
index+=3
bool_index=0
if not self.currentDataParamsConstr is None:
self.currentDataParamsValues=dict()
for params_constr in self.currentDataParamsConstr:
try:
param_key=params_constr['id']
param_type=params_constr['type']
value=None
if param_type!=CURRENT_DATATYPE_BOOLEAN and bool_index>0:
index+=CURRENT_DATA_TYPES_LEN[CURRENT_DATATYPE_BOOLEAN]
bool_index=0
if param_type==CURRENT_DATATYPE_UNDEFINED0:
index+=CURRENT_DATA_TYPES_LEN[CURRENT_DATATYPE_UNDEFINED0]
elif param_type==CURRENT_DATATYPE_SHORT_INT:
value=utils.decodeValByte(msg[index])
index+=CURRENT_DATA_TYPES_LEN[CURRENT_DATATYPE_SHORT_INT]
elif param_type==CURRENT_DATATYPE_INT:
value=utils.decodeValShort(msg[index:index+2])
index+=CURRENT_DATA_TYPES_LEN[CURRENT_DATATYPE_INT]
elif param_type==CURRENT_DATATYPE_LONG_INT:
value=utils.decodeLInt(msg[index:index+4])
index+=CURRENT_DATA_TYPES_LEN[CURRENT_DATATYPE_LONG_INT]
elif param_type==CURRENT_DATATYPE_BYTE:
value=ord(msg[index])
index+=CURRENT_DATA_TYPES_LEN[CURRENT_DATATYPE_BYTE]
elif param_type==CURRENT_DATATYPE_WORD:
value=utils.decodeValUShort(msg[index:index+2])
index+=CURRENT_DATA_TYPES_LEN[CURRENT_DATATYPE_WORD]
elif param_type==CURRENT_DATATYPE_DWORD:
value=utils.decodeValDWord(msg[index:index+4])
index+=CURRENT_DATA_TYPES_LEN[CURRENT_DATATYPE_DWORD]
elif param_type==CURRENT_DATATYPE_SHORT_REAL:
value=parseFloat(msg[index:index+4])
index+=CURRENT_DATA_TYPES_LEN[CURRENT_DATATYPE_SHORT_REAL]
elif param_type==CURRENT_DATATYPE_UNDEVINED8:
index+=CURRENT_DATA_TYPES_LEN[CURRENT_DATATYPE_UNDEVINED8]
elif param_type==CURRENT_DATATYPE_LONG_REAL:
value=utils.decodeValDouble(msg[index:index+8])
index+=CURRENT_DATA_TYPES_LEN[CURRENT_DATATYPE_LONG_REAL]
elif param_type==CURRENT_DATATYPE_BOOLEAN:
last_element_bool=True
test=ord(msg[index])
value=bool(test&(1<<bool_index))
bool_index+=CURRENT_DATA_TYPES_LEN[CURRENT_DATATYPE_BOOLEAN]
if bool_index==8:
bool_index=0
index+=CURRENT_DATA_TYPES_LEN[CURRENT_DATATYPE_BOOLEAN]
elif param_type==CURRENT_DATATYPE_BCD:
name=''
while not msg[index]=='\x00':
name+=msg[index]
index+=1
value=name
index+=1
elif param_type==CURRENT_DATATYPE_STRING:
name=''
while not msg[index]=='\x00':
name+=msg[index]
index+=1
if tryUTF8(name):
value=name
else:
value='XXXXXX'
index+=1
elif param_type==CURRENT_DATATYPE_INT_64:
value=utils.decodeValInt64(msg[index:index+8])
index+=CURRENT_DATA_TYPES_LEN[CURRENT_DATATYPE_INT_64]
elif param_type==CURRENT_DATATYPE_UINT_64:
value=utils.decodeValUInt64(msg[index:index+8])
index+=CURRENT_DATA_TYPES_LEN[CURRENT_DATATYPE_UINT_64]
elif param_type==CURRENT_DATATYPE_IPv4:
part1=ord(msg[index])
part2=ord(msg[index+1])
part3=ord(msg[index+2])
part4=ord(msg[index+3])
value=str(part1)+'.'+str(part2)+'.'+str(part3)+'.'+str(part4)
index+=CURRENT_DATA_TYPES_LEN[CURRENT_DATATYPE_IPv4]
elif param_type==CURRENT_DATATYPE_IPv6:
index+=CURRENT_DATA_TYPES_LEN[CURRENT_DATATYPE_IPv6]
self.currentDataParamsValues[param_key]=value
except Exception as ex:
logger.error("parseRegCurrentData(): "+str(ex))
self.parent.setNewCurrentParamsValues(self.currentDataParamsValues)
def parseSettings(self):
AT=AVAILABLE_TILES[self.regType]
len_available_tiles=len(AT)
paramNo=0
tiles=[]
msg=self.message[8:-2]
for byte in msg:
byte=ord(byte)
pos=1
for i in range(8):
if paramNo<len_available_tiles:
if byte&pos!=0:
if AT[paramNo].type_!=state.TileConfig.TYPE_NONE:
if AT[paramNo].memberName_ in CONDITIONAL_TILES_EXTRAS:
AT[paramNo].extra_=CONDITIONAL_TILES_EXTRAS[AT[paramNo].memberName_][self.regType]
if AT[paramNo].memberName_=='mode':
ctrlByte=ord(msg[4])
if ctrlByte==0 or ctrlByte&3==3:
AT[paramNo].extra_=state.CANNOT_CONTROL_BOILER
elif ctrlByte&1==1:
AT[paramNo].extra_=state.CAN_TURN_OFF_BOILER
else:
AT[paramNo].extra_=state.CAN_TURN_ON_BOILER
tiles.append(AT[paramNo])
try:
if AT[paramNo].memberName_=="fuelCons":
state.setFuelConsumptionCalc((byte&pos)!=0)
except Exception as ex:
logger.error("parseSettings(): fuelCons "+str(ex))
pos*=2
paramNo+=1
tiles=sorted(tiles,key=attrgetter('seqNo_'))
self.tiles=tiles
state.setTiles(state.PROTOCOL_EM,tiles)
state.setSchemaID(parseInt(msg[SCHEMA_ID_BYTE_NUMBER-1]))
def parseUID(self):
msg=self.message[8:-2]
try:
self.regType=ord(msg[0])
regProd=utils.decodeValUShort(msg[1:3])
uid_len=ord(msg[3])
prod_logo_idx=4+uid_len
uid=msgToUidStr(msg[4:prod_logo_idx])
reg_logo=utils.decodeValUShort(msg[prod_logo_idx:prod_logo_idx+2])
reg_img=utils.decodeValUShort(msg[prod_logo_idx+2:prod_logo_idx+4])
name_idx=prod_logo_idx+4
reg_name_len=ord(msg[name_idx])
reg_name=msg[name_idx+1:name_idx+1+reg_name_len]
state.setUID(str(uid),str(reg_name),reg_logo,reg_img,self.regType,regProd)
state.setRegAccessState(regProd)
except IndexError:
logger.error("parseUID, invalid message "+utils.toHexString(self.message))
def parseServicePassword(self):
msg=self.message[9:-2]
if len(msg)>0:
state.setServicePassword(str(msg))
def parseWifiParams(self):
try:
msg=self.message[8:-2]
ssid=''
password=''
if len(msg)>0:
securityNo=ord(msg[0])
security=state.ENCRYPTION_UNKNOWN
for k,v in state.ENCRYPTION_NUMBER.items():
if v==securityNo:
security=k
break
ssidLen=ord(msg[1])
if ssidLen>0:
ssid=msg[2:2+ssidLen]
if not tryUTF8(ssid):
ssid='XXXXXX'
passLen=ord(msg[2+ssidLen])
if passLen>0:
password=msg[3+ssidLen:3+ssidLen+passLen]
settings.setWirelessNetwork(ssid,password,security)
except Exception as e:
logger.error("parseWifiParams(): "+str(e))
def parseAlarms(self):
msg=self.message[8:-2]
if len(msg)>0:
allAlarmsNo=ord(msg[0])
idxFirstRead=ord(msg[1])
alarmsNo=ord(msg[2])
if alarmsNo==0:
return
if idxFirstRead==0:
self.alarmsTmp=[]
newAlarms=[]
for i in range(alarmsNo):
shift=3+9*i
code=ord(msg[shift])
fromDate=alarmTimeDecode(struct.unpack('<I',msg[shift+1:shift+5])[0])
if msg[shift+5:shift+9]=='\xff\xff\xff\xff':
toDate=None
else:
toDate=alarmTimeDecode(struct.unpack('<I',msg[shift+5:shift+9])[0])
alarm=state.Alarm(code,fromDate,toDate)
if alarm not in self.alarmsTmp:
self.alarmsTmp.append(alarm)
idxFirstUnread=idxFirstRead+alarmsNo
if idxFirstUnread<allAlarmsNo:
self.parent.queue.addGetAlarms(idxFirstUnread,allAlarmsNo-idxFirstUnread)
else:
state.setAlarms(self.alarmsTmp)
def countMultiply(self,operation,exponent,multiply,unit):
if unit==param.ENUM_UNIT:
return multiply
if operation==0:
return round(float(multiply)*pow(10,exponent),param.DEF_PRECISION)
else:
return round(float(multiply)/pow(10,exponent),param.DEF_PRECISION)
def chooseParamtersTable(self,mixerParams):
if not mixerParams:
return REG_EDITABLE_PARAMS[self.regType]
else:
return REG_MIXERS_PARAMS[self.regType]
def editableParamsDelete(self,paramsEnum):
for i in range(len(paramsEnum)):
paramName=paramsEnum[i]
if paramName in self.editableParams:
del self.editableParams[paramName]
self.parent.setNewEditableParams(self.editableParams)
def ecoSTERindex(self,value,new_length):
if value==0:
return value
full,remainder=divmod(value-1,new_length)
return full*ECOSTER_PARAMS_LEN+remainder+1
def parseParams(self,paramsEnum,mixerParams=False,funky=False):
if paramsEnum is None:
paramsEnum=self.chooseParamtersTable(mixerParams)
undefinedParamPos=0
data=self.message[8:-2]
if data[PARAMS_TABLE_VERSION_INDEX]!=PARAMS_TABLE_VERSION:
logger.warning("Incompatible editable params table version ("+str(data[0])+").")
return
firstParam=ord(data[FIRST_PARAM_INDEX])
i=PARAMS_SHIFT
paramsNo=ord(data[PARAMS_NO_INDEX])
funkylen=None
if funky:
ecosterno=getattr(self.data,'ecoSterNumber',None)
if ecosterno is None or ecosterno==0:
logger.error("Attempting to parse ecoSTER data before we know how many ecoSOLs we have")
return
full,rem=divmod(paramsNo-1,ecosterno)
if rem!=0:
logger.error("we think there are %d ecoSTER, but got %d shared values - not divisible"%(ecosterno,paramsNo-1))
return
funkylen=full
if mixerParams:
mixersNo=ord(data[PARAMS_NO_INDEX+1])
self.mixerParamsNo=paramsNo
paramsNo*=mixersNo
i+=1
changedParams=False
if paramsNo>0:
for p in xrange(firstParam,paramsNo+firstParam):
pp=p
if funky:
pp=self.ecoSTERindex(pp,funkylen)
if pp<len(paramsEnum):
paramName=paramsEnum[pp]
else:
paramName="param_"+str(p)
logger.error("Unknown editable parameter nr "+str(p))
paramSize=DEF_PARAM_SIZE
if paramName in MANY_BYTES_PARAMS:
paramSize=MANY_BYTES_PARAMS[paramName]
parseFunction=PARAMS_PARSE_FUNCTION[paramSize]
value=parseFunction(data[i:i+paramSize])
minv=parseFunction(data[i+paramSize:i+2*paramSize])
maxv=parseFunction(data[i+2*paramSize:i+3*paramSize])
wholeParamData=paramSize*3
if self.isParamValid(data[i:i+wholeParamData]):
if paramName in self.editableParamsDescr:
par=self.editableParamsDescr[paramName]
if par.value!=value or par.minv!=minv or par.maxv!=maxv:
par.value=value
par.minv=minv
par.maxv=maxv
changedParams=True
else:
par=param.Param(value,minv,maxv,sec=254,pos=undefinedParamPos)
undefinedParamPos+=1
self.editableParamsDescr[paramName]=par
changedParams=True
self.editableParams[paramName]=par
self.editableParamsOrigValues[paramName]=par.value
convertToDisplay(par)
if paramName in PARAMETERS_WITH_OFF_POSSIBILITY:
computeParamOffValue(par)
elif paramName in self.editableParams:
del self.editableParams[paramName]
i+=wholeParamData
if changedParams:
self.parent.setNewEditableParams(self.editableParams)
def parseParamsConf(self,paramsEnum,mixerParams=False,funky=False):
if paramsEnum is None:
paramsEnum=self.chooseParamtersTable(mixerParams)
msg=self.message[8:-2]
if len(msg)==0:
return
firstParam=ord(msg[0])
paramsNo=ord(msg[1])
i=2
funkylen=None
if funky:
ecosterno=getattr(self.data,'ecoSterNumber',None)
if ecosterno is None or ecosterno==0:
logger.error("Attempting to parse ecoSTER data before we know how many ecoSOLs we have")
return
full,rem=divmod(paramsNo-1,ecosterno)
if rem!=0:
logger.error("we think there are %d ecoSTER, but got %d shared values - not divisible"%(ecosterno,paramsNo-1))
return
funkylen=full
if mixerParams:
mixerNo=ord(msg[2])
paramsNo*=mixerNo
i+=1
changedParams=False
if paramsNo>0:
for p in xrange(firstParam,firstParam+paramsNo):
unit=ord(msg[i])&31
multOper=ord(msg[i])>>7
exponent=ord(msg[i])>>5&3
mult=ord(msg[i+1])
offset=ord(msg[i+2])
if offset>127:
offset=offset-256
totalMult=self.countMultiply(multOper,exponent,mult,unit)
pp=p
if funky:
pp=self.ecoSTERindex(pp,funkylen)
paramName=paramsEnum[pp]
i+=3
if paramName in self.editableParamsDescr:
par=self.editableParamsDescr[paramName]
if par.unit!=unit or par.mult!=totalMult or par.offset!=offset:
par.unit=unit
par.mult=totalMult
par.offset=offset
changedParams=True
else:
par=param.Param(unit=unit,mult=totalMult,offset=offset)
self.editableParamsDescr[paramName]=par
changedParams=True
if paramName in self.editableParams:
if paramName in self.editableParamsOrigValues:
par.value=self.editableParamsOrigValues[paramName]
convertToDisplay(par)
if paramName in PARAMETERS_WITH_OFF_POSSIBILITY:
computeParamOffValue(par)
if changedParams:
self.parent.setNewEditableParams(self.editableParams)
def parseParamsStruct(self,paramsEnum,mixerParams=False,funky=False):
if paramsEnum is None:
paramsEnum=self.chooseParamtersTable(mixerParams)
msg=self.message[8:-2]
if len(msg)==0:
return
menuVer=ord(msg[0])
firstParam=ord(msg[1])
paramsNo=ord(msg[2])
i=3
funkylen=None
if funky:
ecosterno=getattr(self.data,'ecoSterNumber',None)
if ecosterno is None or ecosterno==0:
logger.error("Attempting to parse ecoSTER data before we know how many ecoSOLs we have")
return
full,rem=divmod(paramsNo-1,ecosterno)
if rem!=0:
logger.error("we think there are %d ecoSTER, but got %d shared values - not divisible"%(ecosterno,paramsNo-1))
return
funkylen=full
logger.warning("setting GLOB_ECOSTER_PARAMS_ACTUAL to %d",full)
global GLOB_ECOSTER_PARAMS_ACTUAL
GLOB_ECOSTER_PARAMS_ACTUAL=full
if mixerParams:
mixerNo=ord(msg[3])
paramsNo*=mixerNo
i+=1
changedParams=False
if paramsNo>0:
for p in xrange(firstParam,firstParam+paramsNo):
sec=ord(msg[i])
pos=ord(msg[i+1])
pp=p
if funky:
pp=self.ecoSTERindex(pp,funkylen)
paramName=paramsEnum[pp]
i+=2
if paramName in self.editableParamsDescr:
par=self.editableParamsDescr[paramName]
if par.sec!=sec or par.pos!=pos:
par.sec=sec
par.pos=pos
changedParams=True
else:
par=param.Param(sec=sec,pos=pos)
self.editableParamsDescr[paramName]=par
changedParams=True
if changedParams:
self.parent.setNewEditableParams(self.editableParams)
def parseNames(self):
msg=self.message[8:-2]
numberOfNamesTypes=ord(msg[0])
index=1
AT=AVAILABLE_TILES[self.regType]
for k in range(len(AT)):
AT[k].name_=None
for i in range(numberOfNamesTypes):
names=[]
nameType=ord(msg[index])
numberOfNames=min(ord(msg[index+1]),PANEL_CIRCUIT_MAX_NUMBER)
nameIndex=ord(msg[index+2])
index+=3
for j in range(numberOfNames):
nameLen=ord(msg[index])
index+=1
if nameLen>0:
name=msg[index:index+nameLen]
names.append(name)
if nameType==CIRCUIT_NAMES:
tileIndex=CIRCUIT_TILES_FIRST_INDEX+j+nameIndex
AT[tileIndex].name_=name
tileIndex=B2_TILES_FIRST_INDEX+j+nameIndex
AT[tileIndex].name_=name
tileIndex=B3_TILES_FIRST_INDEX+j+nameIndex
AT[tileIndex].name_=name
tileIndex=B4_TILES_FIRST_INDEX+j+nameIndex
AT[tileIndex].name_=name
elif nameType==PANEL_NAMES:
tileIndex=PANEL_TILES_FIRST_INDEX+j+nameIndex
AT[tileIndex].name_=name
elif nameType==STER_NAMES:
tileIndex=PANEL_TILES_FIRST_INDEX+j+nameIndex
AT[tileIndex].name_=name
else:
logger.warning("parseNames(): Unknown name type!")
index+=nameLen
self.namesParams[nameType]=names
state.setNames(self.namesParams)
state.setTiles(state.PROTOCOL_EM,self.tiles)
def parseSchedules(self):
msg=self.message[8:-2]
order=self.message[7]
if len(msg)>0:
try:
index=0
t=0
version_num=ord(msg[index])
min_version_num=ord(SCHEDULE_MIN_VERSION)
if version_num>=min_version_num:
blockCount=msg[index+2]
index+=3
currentSchedule=state.getScheduleByLabel(ECOMAX_SCHEDULES)
if order==FRAME_GET_TIME_ZONESANS:
for key in ECOMAX_TIMEZONES_TYPES:
if key in currentSchedule:
currentSchedule.pop(key)
if order==FRAME_GET_ECOSTER_SCHEDULES_ANS:
for key in ECOSTER_TIMESONES_TYPES:
if key in currentSchedule:
currentSchedule.pop(key)
while index<len(msg):
t=ord(msg[index])
schedule_days=[]
scheduleParams=[]
scheduleParams.append(ord(msg[index+1]))
value=ord(msg[index+2])
if value>127:
value=value-256
scheduleParams.append(value)
minval=ord(msg[index+3])
if minval>127:
minval=minval-256
scheduleParams.append(minval)
maxval=ord(msg[index+4])
if maxval>127:
maxval=maxval-256
scheduleParams.append(maxval)
index+=5
lastIndex=index+42
tmpTable=[]
while index<lastIndex:
if len(tmpTable)<6:
tmpTable.append(ord(msg[index]))
else:
schedule_days.append(tmpTable)
tmpTable=[]
tmpTable.append(ord(msg[index]))
index+=1
if len(tmpTable)==6:
schedule_days.append(tmpTable)
schedule_days.append(scheduleParams)
try:
_name=ECOMAXDATA_TIMEZONES_TYPES[t]
if scheduleParams[0]==0 or scheduleParams[0]==1:
currentSchedule[_name]=schedule_days
except Exception as ex:
logger.error("parseSchedules(), Schedule definition error "+str(ex))
state.setScheduleEM(ECOMAX_SCHEDULES,currentSchedule)
except Exception as e:
logger.error("parseSchedules(), Parse Ecomax schedules error "+str(e))
def serveGetRemoteMenu(self,sender,request):
d=FRAME_REMOTE_MENU+chr(request.value)
if not request.extra is None:
if request.value==REMOTE_MENU_NEWPARAM_COMMAND:
element_index=request.extra['param_index']
if element_index<len(self.remoteMenuParamsData):
par=self.remoteMenuParamsData[element_index]
newValue=request.extra['value']
if not par.isInRange(newValue):
logger.warning("Value out of range for param "+request.name+". Given value: "+str(newValue)+". Range: ["+str(par.minv)+","+str(par.maxv)+"].")
return ''
newValue=convertToRegulator(newValue,par)
if 'params_count' in request.extra:
d+=chr(request.extra['params_count'])
if 'param_index' in request.extra:
d+=chr(request.extra['param_index'])
if 'value' in request.extra:
d+=chr(newValue)
else:
return ''
else:
if 'lang' in request.extra:
d+=chr(request.extra['lang'])
if 'count' in request.extra:
d+=request.extra['count']
if 'bindex' in request.extra:
d+=request.extra['bindex']
frame=createEcoNetFrame(sender,d)
return frame
def serveSetCurrentParam(self,sender,request):
frame=''
d=FRAME_SET_CURRPARAM+utils.codeValUShortChr(1)
if not request.extra is None:
param_type=request.extra
param_dataid=request.name
param_value=request.value
d+=chr(param_type)
d+=utils.codeValUShortChr(int(param_dataid))
if param_type==4:
d+=chr(param_value)
frame=createEcoNetFrame(sender,d)
return frame
def parseCurrentParamsEdits(self):
msg=self.message[8:-2]
index=0
paramsNumber=utils.decodeValUShort(msg[index:index+2])
index+=2
self.currentDataParamsEdits.clear()
for i in range(paramsNumber):
param_type=ord(msg[index])
data_id=utils.decodeValUShort(msg[index+1:index+3])
param_desc=dict()
param_desc['type']=param_type
index+=3
if param_type==4:
param_value=ord(msg[index])
param_min=ord(msg[index+1])
param_max=ord(msg[index+2])
param_desc['value']=param_value
param_desc['min']=param_min
param_desc['max']=param_max
self.currentDataParamsEdits[str(data_id)]=param_desc
type_size=CURRENT_DATA_TYPES_LEN[param_type]
if type_size>0 and param_type!=10 and param_type!=11 and param_type!=12:
index+=(3*type_size)
self.parent.setNewCurrentParamsEdits(self.currentDataParamsEdits)
def parseCurrentParamsConstr(self):
msg=self.message[8:-2]
index=0
integrity_blocks_count=utils.decodeValUShort(msg[index:index+2])
index+=2
if integrity_blocks_count>0:
self.currentDataParamsConstr=[]
for i in range(integrity_blocks_count):
param_type=ord(msg[index])
param_id=utils.decodeValUShort(msg[index+1:index+3])
param_constr=dict()
param_constr['id']=param_id
param_constr['type']=param_type
index+=3
self.currentDataParamsConstr.append(param_constr)
def setVersionComplete(self,command):
if command in self.remoteMenuCommandsNew:
self.remoteMenuCommandsRcv[command]=self.remoteMenuCommandsNew[command]
del self.remoteMenuCommandsNew[command]
def commandInOrd(self,command,lang):
for i in range(len(self.remoteMenuCommandsNewOrd)):
command_element=self.remoteMenuCommandsNewOrd[i]
if command_element['command']==command and command_element['lang']==lang:
return True
return False
def removeCommandElement(self,command):
for i in range(len(self.remoteMenuCommandsNewOrd)):
command_element=self.remoteMenuCommandsNewOrd[i]
if command_element['command']==command:
self.remoteMenuCommandsNewOrd.remove(command_element)
break
def setCommandInOrderComplete(self,command):
self.removeCommandElement(command)
def setNewVersion(self,command,addOrd=True,srv=False,lang=None):
command_key=chr(command)
if not command_key in self.remoteMenuCommandsNew and command_key in self.remoteMenuCommandsRcv:
self.remoteMenuCommandsNew[command_key]=self.remoteMenuCommandsRcv[command_key]
if not self.commandInOrd(command,lang)and addOrd:
if srv:
self.addCommandToOrdSrv(command,lang)
else:
self.addCommandToOrd(command,lang)
def langIsInMissingList(self,lang_element,command):
if not lang_element is None and len(self.remoteMenuMissingLangs)>0:
for i in range(len(self.remoteMenuMissingLangs)):
missing_lang=self.remoteMenuMissingLangs[i]
if missing_lang['lang']==lang_element['version']and missing_lang['command']==command:
return True
return False
def getLangElement(self,lang_index):
if len(self.remoteMenuLangs)>lang_index:
lang_element=self.remoteMenuLangs[lang_index]
return lang_element
return None
def getLangCode(self,lang_index):
if len(self.remoteMenuLangs)>lang_index:
lang_element=self.remoteMenuLangs[lang_index]
if not lang_element is None and 'code' in lang_element:
return lang_element['code']
return None
def getLangVersion(self,lang_index):
if len(self.remoteMenuLangs)>lang_index:
lang_element=self.remoteMenuLangs[lang_index]
if not lang_element is None and 'version' in lang_element:
return lang_element['version']
return None
def getLangIndexByVer(self,lang_version):
for i in range(len(self.remoteMenuLangs)):
lang_element=self.remoteMenuLangs[i]
if lang_element['version']==lang_version:
return i
return-1
def saveReadData(self,lang,currentparams,command):
command_key=chr(command)
if lang==self.remoteMenuLangIndex:
self.setVersionComplete(command_key)
self.parent.setNewRemoteMenuData(command,currentparams,self.remoteMenuCommandsRcv[command_key],lang)
if not self.dataInterface is None:
self.dataInterface.storeDataInFile(command,self.remoteMenuCommandsRcv[command_key],currentparams,self.getLangElement(lang))
def updateCRC(self,data,command,current=True):
if current:
if len(self.remoteMenuCRC)>command:
if self.remoteMenuCRC[command]!=0:
self.remoteMenuCRC[command]=zlib.crc32(data,self.remoteMenuCRC[command])&0xFFFFFFFF
else:
self.remoteMenuCRC[command]=zlib.crc32(data)&0xFFFFFFFF
else:
if len(self.remoteMenuDataToSrvCRC)>command:
if self.remoteMenuDataToSrvCRC[command]!=0:
self.remoteMenuDataToSrvCRC[command]=zlib.crc32(data,self.remoteMenuDataToSrvCRC[command])&0xFFFFFFFF
else:
self.remoteMenuDataToSrvCRC[command]=zlib.crc32(data)&0xFFFFFFFF
def isExpectedCommand(self,command,extra):
if 'command' in self.remoteMenuNextCommand and self.remoteMenuNextCommand['command']==command and 'extra' in self.remoteMenuNextCommand and self.remoteMenuNextCommand['extra']==extra:
return True
return False
def switchRemoteMenuRequestOnQueue(self,option=0,extra=None,lang=0,bindex=0):
if not self.configDownloadProcessInProgress:
self.parent.queue.removeGetRemoteMenu(option,extra)
newoption,newextra=self.getNextRemoteMenuCommand(lang,bindex)
if newoption!=0 or newextra!=None:
self.addNewVersionRequestToQueue(FRAME_REMOTE_MENU,newoption,newextra)
else:
if not self.remoteMenuCurrentServerLang is None:
self.storeRemoteMenuSrvData()
self.storeRemoteMenuData()
def getNextRemoteMenuCommand(self,lang,bindex):
if 'command' in self.remoteMenuNextCommand and 'extra' in self.remoteMenuNextCommand:
newcommand=0
newextra=None
lang=0
if len(self.remoteMenuCommandsNewOrd)>0:
newcommand_element=self.remoteMenuCommandsNewOrd[0]
newcommand=newcommand_element['command']
lang=newcommand_element['lang']
if lang<0:
lang=self.remoteMenuLangIndex
if lang<0 or lang>255:
lang=0
if newcommand in[2,7,8,12,13,14,15]:
newextra={'lang':lang,'count':'\xff','bindex':chr(bindex)}
if newcommand==4:
newextra={'count':'\xff','bindex':chr(bindex)}
if newcommand==6:
newextra={'lang':lang}
if newcommand==11:
newextra={'lang':lang,'count':'\xff\xff','bindex':utils.codeValUShortChr(bindex)}
return newcommand,newextra
def tryLoadDataFromFiles(self,readCRC,readLangVersion):
current_lang_element=self.getLangElement(self.remoteMenuLangIndex)
if current_lang_element['version']==readLangVersion:
for i in range(len(REMOTE_MENU_LANG_COMMANDS)):
command=REMOTE_MENU_LANG_COMMANDS[i]
read_data=None
if not self.dataInterface is None and chr(command)in self.remoteMenuCommandsNew and not chr(command)in self.remoteMenuCommandsRcv:
read_data=self.dataInterface.findInFiles(command)
if not read_data is None:
self.parent.setNewRemoteMenuData(command,read_data,self.remoteMenuCommandsNew[chr(command)])
if not readCRC is None and len(readCRC)>command:
self.remoteMenuCRC[command]=readCRC[command]
self.setVersionComplete(chr(command))
self.setCommandInOrderComplete(command)
def addDataToBuffer(self,data_buffer,index,value,defaultvalue='---'):
table_size=len(data_buffer)
if table_size<index:
while len(data_buffer)<=index:
data_buffer.append(defaultvalue)
table_size=len(data_buffer)
if table_size==index:
data_buffer.append(value)
if table_size>index:
data_buffer[index]=value
def addCommandToOrd(self,command,lang=-1):
command_element=dict()
command_element['command']=command
command_element['lang']=lang
self.remoteMenuCommandsNewOrd.append(command_element)
self.remoteMenuCRC[command]=0
def addCommandToOrdSrv(self,command,lang=None):
command_element=dict()
command_element['command']=command
command_element['lang']=lang
self.remoteMenuCommandsNewOrd.append(command_element)
self.remoteMenuDataToSrvCRC[command]=0
def setRemoteMenuLang(self):
saved_lang=state.getRemoteMenuLang()
change_lang_flag=False
if saved_lang=='default':
if self.remoteMenuLangIndex!=self.remoteMenuDefaultLangIndex:
change_lang_flag=True
self.remoteMenuLangIndex=self.remoteMenuDefaultLangIndex
else:
for i in range(len(self.remoteMenuLangs)):
lang_element=self.remoteMenuLangs[i]
if 'code' in lang_element and lang_element['code']==saved_lang:
if self.remoteMenuLangIndex!=i:
change_lang_flag=True
self.remoteMenuLangIndex=i
if not self.dataInterface is None:
self.dataInterface.storeSettingsDataInFile('langindex',self.remoteMenuLangIndex)
return change_lang_flag
def parseRemoteMenu(self):
msg=self.message[8:-2]
extra=None
command_key=msg[0]
command=ord(command_key)
if self.dataInterface is None:
self.dataInterface=datafile.DataFile()
if command==0:
index=1
version=str(ord(msg[index+1]))+"."+str(ord(msg[index]))
if self.isExpectedCommand(command,extra):
if version==REMOTE_MENU_VERSION:
commandsNumber=ord(msg[index+2])
index+=3
for i in range(commandsNumber):
command_name=msg[index]
command_version=utils.decodeValUShort(msg[index+1:index+3])
if ord(command_name)in REMOTE_MENU_ALLOWED_COMMANDS:
if command_name in self.remoteMenuCommandsRcv:
if self.remoteMenuCommandsRcv[command_name]!=command_version:
self.remoteMenuCommandsNew[command_name]=command_version
if ord(command_name)!=0:
self.addCommandToOrd(ord(command_name))
else:
self.remoteMenuCommandsNew[command_name]=command_version
if ord(command_name)!=0:
self.addCommandToOrd(ord(command_name))
index+=3
self.switchRemoteMenuRequestOnQueue(command,extra,self.remoteMenuLangIndex)
elif command==1:
if self.isExpectedCommand(command,extra):
readCRC=None
readLangVersion=None
self.remoteMenuSavedSettings=self.dataInterface.getSettingsDataFromFile()
if not self.remoteMenuSavedSettings is None:
if 'lang' in self.remoteMenuSavedSettings:
state.setRemoteMenuLang(self.remoteMenuSavedSettings['lang'])
if 'langindex' in self.remoteMenuSavedSettings:
self.remoteMenuDefaultLangIndex=self.remoteMenuSavedSettings['langindex']
if 'commandscrc' in self.remoteMenuSavedSettings:
readCRC=self.remoteMenuSavedSettings['commandscrc']
if 'lang_version' in self.remoteMenuSavedSettings:
readLangVersion=self.remoteMenuSavedSettings['lang_version']
index=1
langsNumber=ord(msg[index])
regDefLang=ord(msg[index+1])
defaultChange=False
if self.remoteMenuDefaultLangIndex!=regDefLang:
defaultChange=True
self.remoteMenuLangIndex=self.remoteMenuDefaultLangIndex=regDefLang
self.remoteMenuLangs=[]
self.remoteMenuFramesSend=[]
index+=2
for i in range(langsNumber):
code=''
name=''
lang=dict()
while not msg[index]=='\x00':
code+=msg[index]
index+=1
index+=1
lang['code']=code
while not msg[index]=='\x00':
name+=msg[index]
index+=1
index+=1
lang['name']=name
lang['version']=utils.toHexStringNoSep(msg[index:index+4])
if i==regDefLang:
lang['default']=True
index+=4
self.remoteMenuLangs.append(lang)
self.setRemoteMenuLang()
if defaultChange and self.remoteMenuLangIndex==self.remoteMenuDefaultLangIndex:
for index in range(len(REMOTE_MENU_LANG_COMMANDS)):
self.setNewVersion(REMOTE_MENU_LANG_COMMANDS[index],lang=self.remoteMenuLangIndex)
else:
self.tryLoadDataFromFiles(readCRC,readLangVersion)
self.setVersionComplete(command_key)
self.setCommandInOrderComplete(command)
self.parent.setNewRemoteMenuData(command,self.remoteMenuLangs,self.remoteMenuCommandsRcv[command_key])
self.switchRemoteMenuRequestOnQueue(command,extra,self.remoteMenuLangIndex)
elif command==2:
index=1
lang=ord(msg[index])
paramNamesNumber=ord(msg[index+1])
beginIndex=ord(msg[index+2])
extra={'lang':lang,'count':'\xff','bindex':chr(beginIndex)}
if self.isExpectedCommand(command,extra):
if beginIndex==0:
self.remoteMenuCurrReadLangIndex=lang
self.remoteMenuLangsData=[]
index+=3
nameIndex=beginIndex
for i in range(paramNamesNumber):
name=''
name_len=0
while not msg[index]=='\x00':
name+=msg[index]
index+=1
try:
name.decode('utf-8')
except UnicodeError:
name='XXXXXX'
name=name.replace(b'%%',b'%')
if lang==self.remoteMenuLangIndex:
self.addDataToBuffer(self.remoteMenuParamsNames,nameIndex,name)
if lang==self.remoteMenuCurrReadLangIndex:
self.remoteMenuLangsData.append(name)
index+=1
nameIndex+=1
if lang==self.remoteMenuCurrReadLangIndex:
self.updateCRC(self.message[12:-2],command,(lang==self.remoteMenuLangIndex))
if paramNamesNumber==0 and lang==self.remoteMenuCurrReadLangIndex:
self.setCommandInOrderComplete(command)
self.saveRemoteMenuToSrvData(lang,command)
beginIndex=0
self.switchRemoteMenuRequestOnQueue(command,extra,lang,(beginIndex+paramNamesNumber))
elif command==3:
if self.isExpectedCommand(command,extra):
index=1
paramKonfNumber=ord(msg[index])
index+=1
for i in range(paramKonfNumber):
unit=ord(msg[index])&31
multOper=ord(msg[index])>>7
exponent=ord(msg[index])>>5&3
mult=ord(msg[index+1])
offset=ord(msg[index+2])
index+=3
if offset>127:
offset=offset-256
totalMult=self.countMultiply(multOper,exponent,mult,unit)
if i<len(self.remoteMenuParamsData):
par=self.remoteMenuParamsData[i]
par.unit=unit
par.mult=totalMult
par.offset=offset
convertToDisplayRM(par)
else:
par=param.Param(unit=unit,mult=totalMult,offset=offset,sec=-1,pos=-1)
self.remoteMenuParamsData.append(par)
self.setVersionComplete(command_key)
self.setCommandInOrderComplete(command)
self.parent.setNewRemoteMenuData(command,self.remoteMenuParamsData,self.remoteMenuCommandsRcv[command_key])
self.switchRemoteMenuRequestOnQueue(command,extra,self.remoteMenuLangIndex)
elif command==4:
index=1
paramValuesNumber=ord(msg[index])
beginIndex=ord(msg[index+1])
extra={'count':'\xff','bindex':chr(beginIndex)}
if self.isExpectedCommand(command,extra):
index+=2
for i in range(paramValuesNumber):
value=ord(msg[index])
minv=ord(msg[index+1])
maxv=ord(msg[index+2])
index+=3
if i<len(self.remoteMenuParamsData):
par=self.remoteMenuParamsData[i]
par.orgvalue=value
par.orgminv=minv
par.orgmaxv=maxv
convertToDisplayRM(par)
else:
par=param.Param(value,minv,maxv,sec=-1,pos=-1,orgvalue=value,orgminv=minv,orgmaxv=maxv)
self.remoteMenuParamsData.append(par)
if paramValuesNumber==0:
self.setVersionComplete(command_key)
self.setCommandInOrderComplete(command)
self.parent.setNewRemoteMenuData(command,self.remoteMenuParamsData,self.remoteMenuCommandsRcv[command_key])
beginIndex=0
self.switchRemoteMenuRequestOnQueue(command,extra,self.remoteMenuLangIndex,(beginIndex+paramValuesNumber))
elif command==5:
pass
elif command==6:
self.remoteMenuParamsUnits=[]
index=1
lang=ord(msg[index])
extra={'lang':lang}
if self.isExpectedCommand(command,extra):
unitNamesNumber=ord(msg[index+1])
self.remoteMenuCurrReadLangIndex=lang
self.remoteMenuLangsData=[]
index+=2
for i in range(unitNamesNumber):
name=''
while not msg[index]=='\x00':
name+=msg[index]
index+=1
try:
name.decode('utf-8')
except UnicodeError:
name='XXXXXX'
name=name.replace(b'%%',b'%')
if lang==self.remoteMenuLangIndex:
self.remoteMenuParamsUnits.append(name)
if lang==self.remoteMenuCurrReadLangIndex:
self.remoteMenuLangsData.append(name)
index+=1
if lang==self.remoteMenuCurrReadLangIndex:
self.updateCRC(self.message[11:-2],command,(lang==self.remoteMenuLangIndex))
self.setCommandInOrderComplete(command)
self.saveRemoteMenuToSrvData(lang,command)
self.switchRemoteMenuRequestOnQueue(command,extra,lang)
elif command==7:
index=1
lang=ord(msg[index])
enumNamesNumber=ord(msg[index+1])
beginIndex=ord(msg[index+2])
extra={'lang':lang,'count':'\xff','bindex':chr(beginIndex)}
if self.isExpectedCommand(command,extra):
if beginIndex==0:
self.remoteMenuCurrReadLangIndex=lang
self.remoteMenuLangsData=[]
index+=3
for i in range(enumNamesNumber):
enum_size=ord(msg[index])
enum_first=ord(msg[index+1])
enum_element=dict()
enum_element['first']=enum_first
index+=2
enum_names=[]
for i in range(enum_size):
name=''
while not msg[index]=='\x00':
name+=msg[index]
index+=1
try:
name.decode('utf-8')
except UnicodeError:
name='XXXXXX'
name=name.replace(b'%%',b'%')
enum_names.append(name)
index+=1
enum_element['values']=enum_names
if lang==self.remoteMenuLangIndex:
self.remoteMenuParamsEnums.append(enum_element)
if lang==self.remoteMenuCurrReadLangIndex:
self.remoteMenuLangsData.append(enum_element)
if lang==self.remoteMenuCurrReadLangIndex:
self.updateCRC(self.message[12:-2],command,(lang==self.remoteMenuLangIndex))
if enumNamesNumber==0:
self.setCommandInOrderComplete(command)
self.saveRemoteMenuToSrvData(lang,command)
beginIndex=0
self.switchRemoteMenuRequestOnQueue(command,extra,lang,(beginIndex+enumNamesNumber))
elif command==8:
index=1
lang=ord(msg[index])
catNamesNumber=ord(msg[index+1])
beginIndex=ord(msg[index+2])
extra={'lang':lang,'count':'\xff','bindex':chr(beginIndex)}
if self.isExpectedCommand(command,extra):
if beginIndex==0:
self.remoteMenuCurrReadLangIndex=lang
self.remoteMenuLangsData=[]
index+=3
nameIndex=beginIndex
for i in range(catNamesNumber):
name=''
while not msg[index]=='\x00':
name+=msg[index]
index+=1
try:
name.decode('utf-8')
except UnicodeError:
name='XXXXXX'
name=name.replace(b'%%',b'%')
if lang==self.remoteMenuLangIndex:
self.addDataToBuffer(self.remoteMenuCatsNames,nameIndex,name)
if lang==self.remoteMenuCurrReadLangIndex:
self.remoteMenuLangsData.append(name)
index+=1
nameIndex+=1
if lang==self.remoteMenuCurrReadLangIndex:
self.updateCRC(self.message[12:-2],command,(lang==self.remoteMenuLangIndex))
if catNamesNumber==0:
self.setCommandInOrderComplete(command)
self.saveRemoteMenuToSrvData(lang,command)
beginIndex=0
self.switchRemoteMenuRequestOnQueue(command,extra,lang,(beginIndex+catNamesNumber))
elif command==9:
if self.isExpectedCommand(command,extra):
index=1
self.remoteMenuStructure=[]
konfNumber=utils.decodeValUShort(msg[index:index+2])
delete_cats=[]
parents_iterator=0
child_counter_iterator=0
index+=2
i=0
while i<konfNumber:
menu_struct_element=dict()
konf_attr=ord(msg[index])
element_index=ord(msg[index+1])
curr_data_id=None
pass_index,lock,element_type_value=self.getRemoteMenuElementDetails(konf_attr)
if element_type_value==7:
if i>2:
child_counter_iterator+=1
if element_type_value==0 or element_type_value==2 or element_type_value==4 or element_type_value==5:
if element_type_value==4 or((element_type_value==0 or element_type_value==2 or element_type_value==5)and child_counter_iterator in delete_cats):
delete_cats.append(parents_iterator)
parents_iterator+=1
if element_type_value==3 and i<konfNumber-1:
data_id_value=msg[index+1]+msg[index+3]
curr_data_id=utils.decodeValUShort(data_id_value)
index+=2
i+=1
menu_struct_element['index']=element_index
menu_struct_element['pass_index']=pass_index
menu_struct_element['lock']=lock
menu_struct_element['type']=element_type_value
if lock and(i+1)<(konfNumber-1):
menu_struct_element['lock_index']=ord(msg[index+3])
index+=2
i+=1
if not curr_data_id is None:
menu_struct_element['data_id']=str(curr_data_id)
if element_type_value!=4 and not child_counter_iterator in delete_cats:
self.remoteMenuStructure.append(menu_struct_element)
index+=2
i+=1
self.setVersionComplete(command_key)
self.setCommandInOrderComplete(command)
self.parent.setNewRemoteMenuData(command,self.remoteMenuStructure,self.remoteMenuCommandsRcv[command_key])
self.switchRemoteMenuRequestOnQueue(command,extra,self.remoteMenuLangIndex)
elif command==10:
if self.isExpectedCommand(command,extra):
index=1
passNumber=ord(msg[index])
index+=1
for i in range(passNumber):
edit_password=utils.decodeValUShort(msg[index:index+2])
view_password=utils.decodeValUShort(msg[index+2:index+4])
password=dict()
password['edit']=edit_password
password['view']=view_password
index+=4
self.remoteMenuPasswords.append(password)
self.setVersionComplete(command_key)
self.setCommandInOrderComplete(command)
self.parent.setNewRemoteMenuData(command,self.remoteMenuPasswords,self.remoteMenuCommandsRcv[command_key])
state.setRemoteMenuPasswords(self.remoteMenuPasswords)
self.switchRemoteMenuRequestOnQueue(command,extra,self.remoteMenuLangIndex)
elif command==11:
index=1
lang=ord(msg[index])
currDataNamesNumber=utils.decodeValUShort(msg[index+1:index+3])
index+=3
beginIndex=utils.decodeValUShort(msg[index:index+2])
index+=2
extra={'lang':lang,'count':'\xff\xff','bindex':utils.codeValUShortChr(beginIndex)}
if self.isExpectedCommand(command,extra):
if beginIndex==0:
self.remoteMenuCurrReadLangIndex=lang
self.remoteMenuLangsData={}
for i in range(currDataNamesNumber):
curr_data_element=dict()
data_id=utils.decodeValUShort(msg[index:index+2])
index+=2
unit=ord(msg[index])
special=ord(msg[index+1])
index+=2
name=''
while not msg[index]=='\x00':
name+=msg[index]
index+=1
try:
name.decode('utf-8')
except UnicodeError:
name='XXXXXX'
name=name.replace(b'%%',b'%')
curr_data_element['name']=str(name)
curr_data_element['unit']=unit
curr_data_element['special']=special
if lang==self.remoteMenuLangIndex:
self.currentDataDispParams[str(data_id)]=curr_data_element
if lang==self.remoteMenuCurrReadLangIndex:
self.remoteMenuLangsData[str(data_id)]=curr_data_element
index+=1
if lang==self.remoteMenuCurrReadLangIndex:
self.updateCRC(self.message[14:-2],command,(lang==self.remoteMenuLangIndex))
if currDataNamesNumber==0:
self.setCommandInOrderComplete(command)
self.saveRemoteMenuToSrvData(lang,command)
beginIndex=0
self.switchRemoteMenuRequestOnQueue(command,extra,lang,(beginIndex+currDataNamesNumber))
elif command==12:
index=1
lang=ord(msg[index])
alarmsNamesNumber=ord(msg[index+1])
beginIndex=ord(msg[index+2])
extra={'lang':lang,'count':'\xff','bindex':chr(beginIndex)}
if self.isExpectedCommand(command,extra):
if beginIndex==0:
self.remoteMenuCurrReadLangIndex=lang
self.remoteMenuLangsData={}
index+=3
for i in range(alarmsNamesNumber):
name=''
alarm_id=ord(msg[index])
index+=1
while not msg[index]=='\x00':
name+=msg[index]
index+=1
try:
name.decode('utf-8')
except UnicodeError:
name='XXXXXX'
name=name.replace(b'%%',b'%')
if lang==self.remoteMenuLangIndex:
self.remoteMenuAlarmsNames[str(alarm_id)]=name
if lang==self.remoteMenuCurrReadLangIndex:
self.remoteMenuLangsData[str(alarm_id)]=name
index+=1
if lang==self.remoteMenuCurrReadLangIndex:
self.updateCRC(self.message[12:-2],command,(lang==self.remoteMenuLangIndex))
if alarmsNamesNumber==0:
self.setCommandInOrderComplete(command)
self.saveRemoteMenuToSrvData(lang,command)
beginIndex=0
self.switchRemoteMenuRequestOnQueue(command,extra,lang,(beginIndex+alarmsNamesNumber))
elif command==13:
index=1
lang=ord(msg[index])
paramsDescNumber=ord(msg[index+1])
beginIndex=ord(msg[index+2])
extra={'lang':lang,'count':'\xff','bindex':chr(beginIndex)}
if self.isExpectedCommand(command,extra):
if beginIndex==0:
self.remoteMenuCurrReadLangIndex=lang
self.remoteMenuLangsData=[]
index+=3
for i in range(paramsDescNumber):
name=''
while not msg[index]=='\x00':
name+=msg[index]
index+=1
try:
name.decode('utf-8')
except UnicodeError:
name='XXXXXX'
name=name.replace(b'%%',b'%')
if lang==self.remoteMenuLangIndex:
self.remoteMenuParamsDescs.append(name)
if lang==self.remoteMenuCurrReadLangIndex:
self.remoteMenuLangsData.append(name)
index+=1
if lang==self.remoteMenuCurrReadLangIndex:
self.updateCRC(self.message[12:-2],command,(lang==self.remoteMenuLangIndex))
if paramsDescNumber==0:
self.setCommandInOrderComplete(command)
self.saveRemoteMenuToSrvData(lang,command)
beginIndex=0
self.switchRemoteMenuRequestOnQueue(command,extra,lang,(beginIndex+paramsDescNumber))
elif command==14:
index=1
lang=ord(msg[index])
catsDescNumber=ord(msg[index+1])
beginIndex=ord(msg[index+2])
extra={'lang':lang,'count':'\xff','bindex':chr(beginIndex)}
if self.isExpectedCommand(command,extra):
if beginIndex==0:
self.remoteMenuCurrReadLangIndex=lang
self.remoteMenuLangsData=[]
index+=3
for i in range(catsDescNumber):
name=''
while not msg[index]=='\x00':
name+=msg[index]
index+=1
try:
name.decode('utf-8')
except UnicodeError:
name='XXXXXX'
name=name.replace(b'%%',b'%')
if lang==self.remoteMenuLangIndex:
self.remoteMenuCatsDescs.append(name)
if lang==self.remoteMenuCurrReadLangIndex:
self.remoteMenuLangsData.append(name)
index+=1
if lang==self.remoteMenuCurrReadLangIndex:
self.updateCRC(self.message[12:-2],command,(lang==self.remoteMenuLangIndex))
if catsDescNumber==0:
self.setCommandInOrderComplete(command)
self.saveRemoteMenuToSrvData(lang,command)
beginIndex=0
self.switchRemoteMenuRequestOnQueue(command,extra,lang,(beginIndex+catsDescNumber))
elif command==15:
index=1
lang=ord(msg[index])
locksNamesNumber=ord(msg[index+1])
beginIndex=ord(msg[index+2])
extra={'lang':lang,'count':'\xff','bindex':chr(beginIndex)}
if self.isExpectedCommand(command,extra):
if beginIndex==0:
self.remoteMenuCurrReadLangIndex=lang
self.remoteMenuLangsData=[]
index+=3
for i in range(locksNamesNumber):
name=''
while not msg[index]=='\x00':
name+=msg[index]
index+=1
try:
name.decode('utf-8')
except UnicodeError:
name='XXXXXX'
name=name.replace(b'%%',b'%')
if lang==self.remoteMenuLangIndex:
self.remoteMenuLocksNames.append(name)
if lang==self.remoteMenuCurrReadLangIndex:
self.remoteMenuLangsData.append(name)
index+=1
if lang==self.remoteMenuCurrReadLangIndex:
self.updateCRC(self.message[12:-2],command,(lang==self.remoteMenuLangIndex))
if locksNamesNumber==0:
self.setCommandInOrderComplete(command)
self.saveRemoteMenuToSrvData(lang,command)
beginIndex=0
self.switchRemoteMenuRequestOnQueue(command,extra,lang,(beginIndex+locksNamesNumber))
else:
self.setVersionComplete(command_key)
if len(self.remoteMenuCommandsNew)==1 and '\x00' in self.remoteMenuCommandsNew:
return True
return None
def storeRemoteMenuData(self):
crcbuff=''
for i in range(len(self.remoteMenuCRC)):
crcbuff+=struct.pack('<I',self.remoteMenuCRC[i])
fullcrc=zlib.crc32(crcbuff)&0xFFFFFFFF
readCRC=utils.toHexStringNoSep(struct.pack('<I',fullcrc))
currLangCRC=self.getLangVersion(self.remoteMenuLangIndex)
if currLangCRC==readCRC:
if not self.dataInterface is None:
self.dataInterface.storeSettingsDataInFile('commandscrc',self.remoteMenuCRC)
if len(self.remoteMenuParamsNames)>0:
self.setVersionComplete(chr(2))
self.saveReadData(self.remoteMenuLangIndex,self.remoteMenuParamsNames,2)
self.remoteMenuParamsNames=[]
if len(self.remoteMenuParamsUnits)>0:
self.setVersionComplete(chr(6))
self.saveReadData(self.remoteMenuLangIndex,self.remoteMenuParamsUnits,6)
self.remoteMenuParamsUnits=[]
if len(self.remoteMenuParamsEnums)>0:
self.setVersionComplete(chr(7))
self.saveReadData(self.remoteMenuLangIndex,self.remoteMenuParamsEnums,7)
self.remoteMenuParamsEnums=[]
if len(self.remoteMenuCatsNames)>0:
self.setVersionComplete(chr(8))
self.saveReadData(self.remoteMenuLangIndex,self.remoteMenuCatsNames,8)
self.remoteMenuCatsNames=[]
if bool(self.currentDataDispParams)>0:
self.setVersionComplete(chr(11))
self.saveReadData(self.remoteMenuLangIndex,self.currentDataDispParams,11)
self.currentDataDispParams={}
if bool(self.remoteMenuAlarmsNames)>0:
self.setVersionComplete(chr(12))
self.saveReadData(self.remoteMenuLangIndex,self.remoteMenuAlarmsNames,12)
self.remoteMenuAlarmsNames={}
if len(self.remoteMenuParamsDescs)>0:
self.setVersionComplete(chr(13))
self.saveReadData(self.remoteMenuLangIndex,self.remoteMenuParamsDescs,13)
self.remoteMenuParamsDescs=[]
if len(self.remoteMenuCatsDescs)>0:
self.setVersionComplete(chr(14))
self.saveReadData(self.remoteMenuLangIndex,self.remoteMenuCatsDescs,14)
self.remoteMenuCatsDescs=[]
if len(self.remoteMenuLocksNames)>0:
self.setVersionComplete(chr(15))
self.saveReadData(self.remoteMenuLangIndex,self.remoteMenuLocksNames,15)
self.remoteMenuLocksNames=[]
if not self.dataInterface is None:
self.dataInterface.storeSettingsDataInFile('lang_version',self.getLangVersion(self.remoteMenuLangIndex))
self.parent.remoteMenuCurrentLangDownlowading=False
self.setNextCommandDefault()
else:
logger.warning("storeRemoteMenuData(): CRC values are not equals! "+str(currLangCRC)+"/"+str(readCRC))
self.reloadLang()
def storeRemoteMenuSrvData(self):
crcbuff=''
for i in range(len(self.remoteMenuDataToSrvCRC)):
crcbuff+=struct.pack('<I',self.remoteMenuDataToSrvCRC[i])
fullcrc=zlib.crc32(crcbuff)&0xFFFFFFFF
readCRC=utils.toHexStringNoSep(struct.pack('<I',fullcrc))
if self.remoteMenuCurrentServerLang==readCRC:
self.parent.setRemoteMenuLangsData(self.remoteMenuCurrentServerLang,self.remoteMenuLangToSrvData)
self.remoteMenuLangToSrvData=dict()
if self.remoteMenuCurrentServerLang in self.remoteMenuMissingLangs:
self.remoteMenuMissingLangs.remove(self.remoteMenuCurrentServerLang)
if self.remoteMenuCurrentServerLang in self.remoteMenuLangsDownloadCounter:
del self.remoteMenuLangsDownloadCounter[self.remoteMenuCurrentServerLang]
self.remoteMenuCurrentServerLang=None
else:
logger.warning("storeRemoteMenuSrvData(): CRC values are not equals! "+str(self.remoteMenuCurrentServerLang))
if not self.remoteMenuCurrentServerLang in self.remoteMenuLangsDownloadCounter:
self.remoteMenuLangsDownloadCounter[self.remoteMenuCurrentServerLang]=1
else:
tmp_counter=self.remoteMenuLangsDownloadCounter[self.remoteMenuCurrentServerLang]
self.remoteMenuLangsDownloadCounter[self.remoteMenuCurrentServerLang]=tmp_counter+1
if self.remoteMenuLangsDownloadCounter[self.remoteMenuCurrentServerLang]>REMOTE_MENU_SEND_LANG_MAX_COUNT:
self.remoteMenuLockedLangs.append(self.remoteMenuCurrentServerLang)
del self.remoteMenuLangsDownloadCounter[self.remoteMenuCurrentServerLang]
self.remoteMenuCurrentServerLang=None
def saveRemoteMenuToSrvData(self,lang,command):
if not self.parent.remoteMenuCurrentLangDownlowading and not self.remoteMenuCurrentServerLang is None:
key=createLangCode(self.remoteMenuCurrentServerLang,command)
if lang!=self.remoteMenuLangIndex:
self.remoteMenuLangToSrvData[key]=self.remoteMenuLangsData
def saveRemoteMenuToSrvDataFromFile(self,command,data):
if not self.remoteMenuCurrentServerLang is None:
key=createLangCode(self.remoteMenuCurrentServerLang,command)
self.remoteMenuLangToSrvData[key]=data
def getRemoteMenuElementDetails(self,attribute):
password_index=-1
lock=False
element_type_value=-1
if attribute&REMOTE_MENU_PASS7==REMOTE_MENU_PASS7:
password_index=7
elif attribute&REMOTE_MENU_PASS6==REMOTE_MENU_PASS6:
password_index=6
elif attribute&REMOTE_MENU_PASS5==REMOTE_MENU_PASS5:
password_index=5
elif attribute&REMOTE_MENU_PASS4==REMOTE_MENU_PASS4:
password_index=4
elif attribute&REMOTE_MENU_PASS3==REMOTE_MENU_PASS3:
password_index=3
elif attribute&REMOTE_MENU_PASS2==REMOTE_MENU_PASS2:
password_index=2
elif attribute&REMOTE_MENU_PASS1==REMOTE_MENU_PASS1:
password_index=1
elif attribute&REMOTE_MENU_NOPASSWORD==REMOTE_MENU_NOPASSWORD:
password_index=0
if attribute&REMOTE_MENU_LOCK==REMOTE_MENU_LOCK:
lock=True
if attribute&REMOTE_MENU_CHILDCOUNTER_ELEMENT==REMOTE_MENU_CHILDCOUNTER_ELEMENT:
element_type_value=REMOTE_MENU_CHILDCOUNTER_ELEMENT
elif attribute&REMOTE_MENU_LOCK_ELEMENT==REMOTE_MENU_LOCK_ELEMENT:
element_type_value=REMOTE_MENU_LOCK_ELEMENT
elif attribute&REMOTE_MENU_PASSWORD_ELEMENT==REMOTE_MENU_PASSWORD_ELEMENT:
element_type_value=REMOTE_MENU_PASSWORD_ELEMENT
elif attribute&REMOTE_MENU_ALARMSCAT_ELEMENT==REMOTE_MENU_ALARMSCAT_ELEMENT:
element_type_value=REMOTE_MENU_ALARMSCAT_ELEMENT
elif attribute&REMOTE_MENU_CURRDATA_ELEMENT==REMOTE_MENU_CURRDATA_ELEMENT:
element_type_value=REMOTE_MENU_CURRDATA_ELEMENT
elif attribute&REMOTE_MENU_CURRDATACAT_ELEMENT==REMOTE_MENU_CURRDATACAT_ELEMENT:
element_type_value=REMOTE_MENU_CURRDATACAT_ELEMENT
elif attribute&REMOTE_MENU_PARAM_ELEMENT==REMOTE_MENU_PARAM_ELEMENT:
element_type_value=REMOTE_MENU_PARAM_ELEMENT
elif attribute&REMOTE_MENU_CAT_ELEMENT==REMOTE_MENU_CAT_ELEMENT:
element_type_value=REMOTE_MENU_CAT_ELEMENT
return password_index,lock,element_type_value
def changeLang(self,lang):
state.setRemoteMenuLang(lang)
if not self.dataInterface is None:
self.dataInterface.storeSettingsDataInFile('lang',lang)
need_reload=self.setRemoteMenuLang()
if need_reload:
self.reloadLang()
def reloadLang(self):
self.remoteMenuCRC=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
self.remoteMenuDataToSrvCRC=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
self.remoteMenuCommandsNewOrd=[]
self.parent.remoteMenuCurrentLangDownlowading=True
self.remoteMenuCurrentServerLang=None
self.remoteMenuParamsNames=[]
self.remoteMenuParamsUnits=[]
self.remoteMenuParamsEnums=[]
self.remoteMenuCatsNames=[]
self.currentDataDispParams={}
self.remoteMenuAlarmsNames={}
self.remoteMenuParamsDescs=[]
self.remoteMenuCatsDescs=[]
self.remoteMenuLocksNames=[]
for index in range(len(REMOTE_MENU_LANG_COMMANDS)):
self.setNewVersion(REMOTE_MENU_LANG_COMMANDS[index],lang=self.remoteMenuLangIndex)
newoption,newextra=self.getNextRemoteMenuCommand(self.remoteMenuLangIndex,0)
if newoption!=0 or newextra!=None:
self.addNewVersionRequestToQueue(FRAME_REMOTE_MENU,newoption,newextra)
def addMissingLangs(self,missinglangs):
self.remoteMenuMissingLangs=[]
for i in range(len(missinglangs)):
if not missinglangs[i]in self.remoteMenuLockedLangs:
self.remoteMenuMissingLangs.append(missinglangs[i])
if len(missinglangs)==len(self.remoteMenuMissingLangs):
self.remoteMenuLockedLangs=[]
def getAndSendRemoteMenuDataToServer(self):
if len(self.remoteMenuMissingLangs)>0 and not self.parent.remoteMenuCurrentLangDownlowading:
if self.remoteMenuCurrentServerLang is None or self.remoteMenuCurrentServerLang!=self.remoteMenuMissingLangs[0]:
self.remoteMenuCurrentServerLang=self.remoteMenuMissingLangs[0]
if not self.remoteMenuCurrentServerLang in self.remoteMenuLockedLangs:
self.remoteMenuDataToSrvCRC=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
self.remoteMenuLangToSrvData=dict()
lang_index=self.getLangIndexByVer(self.remoteMenuCurrentServerLang)
elements_counter=0
if lang_index>-1:
if lang_index==self.remoteMenuLangIndex:
lang_element=self.getLangElement(lang_index)
if not self.dataInterface is None:
settings=self.dataInterface.getSettingsDataFromFile()
if not settings is None and 'lang_version' in settings and settings['lang_version']==lang_element['version']:
for i in range(len(REMOTE_MENU_LANG_COMMANDS)):
command=REMOTE_MENU_LANG_COMMANDS[i]
read_data=None
if not self.dataInterface is None:
read_data=self.dataInterface.findInFiles(command)
if not read_data is None:
self.saveRemoteMenuToSrvDataFromFile(command,read_data)
elements_counter+=1
if elements_counter==len(REMOTE_MENU_LANG_COMMANDS):
self.parent.setRemoteMenuLangsData(self.remoteMenuCurrentServerLang,self.remoteMenuLangToSrvData)
if self.remoteMenuCurrentServerLang in self.remoteMenuMissingLangs:
self.remoteMenuMissingLangs.remove(self.remoteMenuCurrentServerLang)
else:
extra={'lang':lang_index,'count':'\xff','bindex':chr(0)}
self.addNewVersionRequestToQueue(FRAME_REMOTE_MENU,2,extra)
for index in range(len(REMOTE_MENU_LANG_COMMANDS)):
self.setNewVersion(REMOTE_MENU_LANG_COMMANDS[index],srv=True,lang=lang_index)
else:
self.remoteMenuCurrentServerLang=None
else:
self.remoteMenuCurrentServerLang=None
def checkRemoteMenuCommandProgress(self):
if len(self.remoteMenuCommandsNewOrd)!=0:
if bool(self.remoteMenuNextCommand)and self.remoteMenuNextCommand!=self.remoteMenuPrevCommand:
self.remoteMenuPrevCommand=self.remoteMenuNextCommand
self.remoteMenuCommandProgressCounter=0
else:
self.remoteMenuCommandProgressCounter+=1
if self.remoteMenuCommandProgressCounter>5:
self.addNewVersionRequestToQueue(FRAME_REMOTE_MENU,self.remoteMenuNextCommand['command'],self.remoteMenuNextCommand['extra'])
self.remoteMenuCommandProgressCounter=0
def isFrameValid(self,frame,length):
if length<10:
return False
if frame[0]!=BEGIN_FRAME:
return False
if frame[length-1]!=END_FRAME:
return False
len_dec=queue.shortFromBytes(frame[1],frame[2])
if length!=len_dec:
return False
if frame[length-2]!=crc(frame[0:length-2]):
return False
return True
def getFrameHeaderLen(self):
return 0
def defaultData(self):
self.data=state.DataObj()
return self.data
def newWifiParametersFromEconet(self,ssid,password,security):
pass
def saveFlash(self,sender):
global ECONET_IMAGE
answerFrame=FRAME_SAVE_FLASH_ANS
if self.message[8:12]=='\xff\xff\xff\xff':
self.initSaveingImage()
else:
if self.framesNo:
frameLength=queue.shortFromBytes(self.message[1],self.message[2])
address=utils.intFromBytes(self.message[8:12])
data=utils.toIntTab(self.message[12:-2])
if frameLength==len(self.message)and len(data)%16==0:
self.writeDataToImage(address,data)
self.framesNo=self.framesNo-1
if not self.framesNo:
settings.updateSoftware(ECONET_IMAGE)
else:
answerFrame=FRAME_DATA_SIZE_ERROR
else:
answerFrame=FRAME_NO_INIT_DATA_ERROR
crc=crcLib.crcCCITT(utils.toIntTab(self.message[12:-2]))
return createEcoNetFrame(sender,answerFrame+crc[0]+crc[1])
def writeDataToImage(self,address,data):
global ECONET_IMAGE
for i in range(len(ECONET_IMAGE),address/8+len(data)):
ECONET_IMAGE.append(0xff)
ECONET_IMAGE[address/8:address/8+len(data)]=data
def verifyProgram(self,sender):
global ECONET_IMAGE
beginAddress=utils.intFromBytes(self.message[8:12])/8
endAddress=utils.intFromBytes(self.message[12:16])/8
crc=crcLib.crcCCITT(ECONET_IMAGE[beginAddress:endAddress])
return createEcoNetFrame(sender,FRAME_VERIFY_PROGRAM_ANS+crc[0]+crc[1])
def initSaveingImage(self):
global ECONET_IMAGE
mac=self.message[12:28]
self.framesNo=queue.shortFromBytes(mac[0],mac[1])
del ECONET_IMAGE[:]
def prepareMAC(self):
deviceMac=state.getMAC()
if len(deviceMac)>0:
deviceMac=[int(item,16)for item in deviceMac.split(":")]
else:
deviceMac=[]
mac=''
for i in range(len(deviceMac)):
mac=mac+chr(deviceMac[i])
for i in range(len(deviceMac),16):
mac=mac+'\xff'
return mac
def askForDeviceSoftVer(self):
self.parent.queue.addGetModulesVer()
def parseActualModuleVersions(self):
self.parseModulesVersions(self.message[8:-2])
state.setVersions(self.modulesVersData)
if self.configDownloadProcessInProgress and self.getConfigVersionDownload:
self.getConfigVersionDownload=False
self.parent.queue.addGetDevConfig()
self.modulesVersionSend=False
def parseSchemaIntegrData(self):
pass
def readModulesVersion(self,sender):
self.modulesUpdaterVersionSend=False
modulesConnected=self.parseModulesVersions(self.message[8:-2])
state.setVersions(self.modulesVersData)
while not self.updater.downloadFinished and not self.updater.downloaded==-1:
time.sleep(1)
self.updater.checkSoftware()
if self.updater.module in modulesConnected:
version=modulesConnected[self.updater.module]
logger.info("devSW: %s | pfiSW: %s"%(rsu.v2str(version['sw']),rsu.v2str(self.updater.verSW)))
logger.info("[pfi] minSW: %s | maxSW: %s"%(rsu.v2str(self.updater.minVerSW),rsu.v2str(self.updater.maxVerSW)))
logger.info("devID: %04X | pfiID: %04X"%(version["dev_id"],self.updater.did))
logger.info("devHW: %s | pfiHW: %s"%(rsu.v2str(version['hw']),rsu.v2str(self.updater.verHW)))
logger.info("devSIG: %s | pfiSIG: %s"%(str(version["signature"]),str(self.updater.sig)))
logger.info("pfiDate: "+str(self.updater.date))
updatePermission,errorMsg=self.checkNewSoftCompatibility(version["dev_id"],self.updater.did,version['sw'],self.updater.verSW,version['hw'],self.updater.verHW,self.updater.minVerSW,self.updater.maxVerSW,version["signature"],self.updater.sig)
if updatePermission:
if self.updater.running:
self.updater.oldHW=version['hw']
self.updater.oldSW=version['sw']
try:
self.updater.oldVersionName=self.createSoftInfo(version['date'],version['hw'],version['sw'],version['bw'])
self.updater.versionName=self.createSoftInfo(self.updater.date,self.updater.verHW,self.updater.verSW)
except Exception as e:
logger.error("ver compute error: "+str(e))
if not self.updater.confirmed:
self.updater.setState("version")
if self.updater.configUpdateRunning:
self.startSetConfigData()
else:
self.updater.raiseException(errorMsg)
else:
logger.error("Update: Module not connected "+str(self.updater.module))
self.updater.raiseException("module_not_connected")
def checkNewSoftCompatibility(self,deviceId,pfiDevId,deviceSw,pfiSw,deviceHw,pfiHw,minSwVer,maxSwVer,devSig,pfiSig):
if devSig!=pfiSig:
logger.error("update: devSig: %s, pfiSig: %s"%(devSig,pfiSig))
return False,"proc_type_incompatible(dev:%s,pfi:%s)"%(devSig,pfiSig)
if deviceId!=0 and(deviceId!=pfiDevId)and not compatibleSNAFU(deviceId,pfiDevId,deviceSw,pfiSw):
logger.error("update: devID: 0x%04X, pfiID: 0x%04X"%(deviceId,pfiDevId))
return False,"device_type_incompatible(dev:%04X,pfi:%04X)"%(deviceId,pfiDevId)
if not rsu.vAll(deviceSw)and((rsu.vAgtB(minSwVer,deviceSw)and not rsu.vAll(minSwVer))or(rsu.vAgtB(deviceSw,maxSwVer)and not rsu.vAll(maxSwVer))):
logger.error("devSW: %s, minSW: %s, maxSW: %s"%(rsu.v2str(deviceSw),rsu.v2str(minSwVer),rsu.v2str(maxSwVer)))
return False,"software_version_incompatible(dev:%s,min:%s,max:%s)"%(rsu.v2str(deviceSw),rsu.v2str(minSwVer),rsu.v2str(maxSwVer))
if not rsu.vEq(deviceHw,pfiHw):
if rsu.vgMaj(deviceHw)==rsu.vgMaj(pfiHw):
logger.info("allowing update changing minor HW version: devHW: %s -> pfiHW: %s"%(rsu.v2str(deviceHw),rsu.v2str(pfiHw)))
else:
logger.error("update: devHW: %s, pfiHW: %s"%(rsu.v2str(deviceHw),rsu.v2str(pfiHw)))
return False,"hardware_version_incompatible(dev:%s,pfi:%s)"%(rsu.v2str(deviceHw),rsu.v2str(pfiHw))
return True,""
def createSoftInfo(self,date=None,hw=None,sw=None,bw=None):
sdata=[]
try:
if not hw is None:
sdata.append("HW: %s"%rsu.v2str(hw))
if not sw is None:
sdata.append("SW: %s"%rsu.v2str(sw))
if not bw is None:
sdata.append("BW: %s"%rsu.v2str(bw))
if not date is None:
sdata.append("DATE: %s"%str(date))
except Exception as e:
logger.error("create soft info: "+str(e))
return '; '.join(sdata)
def enterLoaderFrame(self):
passw=0xFFFF&(0x4096^((rsu.v2h(self.updater.oldHW)<<8)|rsu.v2h(self.updater.oldSW)))
passw=struct.pack('<H',passw)
self.sendLoaderQuestion=True
self.updater.setState2("enter_bootloader")
return createEcoNetFrame(self.updater.module,FRAME_ENTER_LOADER+passw)
def enterIntoLoaderAns(self,sender):
if self.sendMasterStopQuestion:
self.masterStopped=True
self.sendMasterStopQuestion=False
if self.sendLoaderQuestion:
self.sendLoaderQuestion=False
return self.checkBootloader(sender)
def checkBootloader(self,sender):
return createBootloaderFrame(FRAME_CONFIRM_LOADER,self.updater.devid if not self.updater is None else '\x68')
def confirmLoaderAns(self,sender):
self.parent.failedLoaderEnterFlag=False
self.parent.failedLoaderEnterCounter=0
if self.updater.pageSendInProgress:
return self.savePage(sender)
else:
if self.sendMasterStopQuestion:
self.masterStopped=True
self.sendMasterStopQuestion=False
if not self.bootLoaderMode:
self.bootLoaderMode=True
if not self.updater.oldSoftDeleted:
return createBootloaderFrame(FRAME_DELETE_SOFTWARE,self.updater.devid if not self.updater is None else '\x68')
def deleteSoftAns(self,sender):
self.updater.setState2("deleted_old_soft")
self.updater.oldSoftDeleted=True
self.updater.pageSendInProgress=True
return self.savePage(sender)
def savePage(self,sender):
data=self.updater.getNextData()
if data is None:
if self.updater.verDataSize:
self.updater.setState2("verify_soft")
return createBootloaderFrame(FRAME_VERIFY_PROGRAM+self.updater.verStartAdr+self.updater.verEndAdr,self.updater.devid if not self.updater is None else '\x68')
else:
self.updater.verified=True
return createBootloaderFrame(FRAME_LEAVE_LOADER,self.updater.devid if not self.updater is None else '\x68')
if self.updater.lastAddressRepNum<=self.parent.REG_SOFT_UPDATE_NO_RESET_REP:
self.parent.lastSaveFlashTime=time.time()
else:
self.parent.lastSaveFlashTime=0
return createBootloaderFrame(FRAME_SAVE_FLASH+data,self.updater.devid if not self.updater is None else '\x68')
def savePageAns(self,sender):
if self.message[8:10]==self.updater.dataCRC:
self.updater.lastAddressRepNum=0
self.parent.lastSaveFlashTime=0
self.parent.updateResetCounter=0
self.updater.updaterReinitRepNum=0
return self.savePage(sender)
self.catchUpdateException(sender,"wrong_crc")
def verifySendedSoftAns(self,sender):
if self.message[8:8+self.updater.verDataSize]==self.updater.verData:
self.parent.updateProcessRepeatCounter=0
self.updater.verified=True
return createBootloaderFrame(FRAME_LEAVE_LOADER,self.updater.devid if not self.updater is None else '\x68')
if self.parent.updateProcessRepeatCounter>=self.parent.REG_SOFT_UPDATE_PROCESS_REP:
self.catchUpdateException(sender,"wrong_ver_data")
else:
self.parent.updateProcessEndFlag=False
self.updater.reinitUpdateParams()
self.parent.reinitUpdateParams()
self.parent.updateProcessRepeatCounter+=1
return self.checkBootloader(sender)
def leaveLoaderAns(self,sender):
self.updater.pageSendInProgress=False
return self.endUpdateProcedure()
def endUpdateProcedure(self):
if self.parent.updateProcessEndFlag:
self.updater.endUpdateError()
else:
if self.masterStopped or self.updater.module!='\x45':
self.bootLoaderMode=False
self.updater.endUpdate(self.actPvVersion)
else:
self.updateEndFlag=True
self.updater.setState("verify_soft")
if self.masterStopped or self.updater.module!='\x45':
return self.startMaster()
def startMaster(self):
return createEcoNetFrame('\x45',FRAME_START_MASTER)
def leaveLoader(self):
createBootloaderFrame(FRAME_LEAVE_LOADER,self.updater.devid if not self.updater is None else '\x68')
def uploadConfig(self,soft_upd=False):
self.resetConfigUploadDataObj()
self.updater.initRegConfigUpload(soft_upd)
self.updater.download()
self.parent.queue.clear()
self.askForDeviceSoftVer()
self.modulesUpdaterVersionSend=True
def updateSoft(self,module):
self.updateEndFlag=False
module_address=getModuleAddress(module)
if not module_address is None:
self.parent.updateResetCounter=0
self.parent.updateProcessEndFlag=False
self.updater.initUpdate(module_address,self.getDeviceIdByLabel(module))
self.updater.download()
self.parent.queue.clear()
self.askForDeviceSoftVer()
self.modulesUpdaterVersionSend=True
else:
self.updater.setState("no module")
self.updater.endUpdate(self.actPvVersion)
def updateSoftConfirmed(self):
self.updater.confirmed=True
if not self.updater.module=='\x45':
self.parent.queue.addStopMaster()
else:
self.parent.queue.addEnterLoader()
def stopMasterFrame(self):
self.sendMasterStopQuestion=True
return createEcoNetFrame('\x45',FRAME_STOP_MASTER)
def parseModulesVersions(self,frame):
self.modulesVersData=[]
modules={}
i=0
struct_ver=0
try:
while i<len(frame):
if frame[i:i+2]=='\xff\xff':
struct_ver=ord(frame[i+2])
i=i+3
else:
struct_ver=0
module=frame[i+STRUCT_SIZE[struct_ver]-1]
modules[module]=STRUCT_PARSE_FUNC[struct_ver](frame[i:i+STRUCT_SIZE[struct_ver]])
i=i+STRUCT_SIZE[struct_ver]
label=getModuleLabel(module)
if module==MODULE_A_CONT_ADDRESS:
self.moduleAVersionData=modules[module]
if not label is None:
self.modulesVersData.append([label,modules[module]['ver_name'],modules[module]['dev_id']])
except Exception as e:
logger.error("parse versions error "+str(e))
self.modulesVersVerifLastDate=time.time()
return modules
def catchUpdateException(self,sender,ex):
self.sendLoaderQuestion=False
if ex=='no init data':
data=self.updater.getInitData()
if not data is None:
return createEcoNetFrame('\x45',FRAME_STOP_MASTER)+createBootloaderFrame(FRAME_SAVE_FLASH+data,self.updater.devid if not self.updater is None else '\x68')
self.updater.raiseException(str(ex).lower().replace(' ','_'))
def startGetConfigData(self):
self.configPfcFile=pfc_file.PfcFile()
self.configDownloadProcessInProgress=True
self.configDownloadProcessCurrIndex=0
self.configDownloadProcessBurnerIndex=0
self.askForDeviceSoftVer()
self.getConfigVersionDownload=True
def resetConfigDataObj(self):
self.configPfcFile=None
self.resetConfigDownloadParam()
def resetConfigDownloadParam(self):
self.configDownloadProcessInProgress=False
self.configDownloadProcessCurrIndex=0
self.configDownloadProcessWaitForCommand=['']
self.configDownloadProcessBurnerIndex=0
self.configDownloadNoSuccessTryCount=0
self.configDownloadSchemaBurnersProfilesCount=0
self.lastConfUploadBurnerIndex=-1
self.lastConfUploadBurnerDataSize=0
def resumeConfigDownloadProcess(self):
if self.configDownloadNoSuccessTryCount<CONFIG_PROCESS_RESUME_COUNT:
self.parent.queue.addGetDevConfig()
self.configDownloadNoSuccessTryCount+=1
else:
if self.configDownloadProcessCurrIndex<len(PATTERN_GET_CONFIG_FRAMES):
if self.configDownloadProcessWaitForCommand==FRAME_GET_CONFIG_BURNERS_ANS:
self.configPfcFile.endLastDataSection()
self.getNextDevConfigFrame()
else:
self.configPfcFile.endPfcFile(version_data=self.moduleAVersionData)
self.resetConfigDownloadParam()
def resumeConfigUploadProcess(self):
if self.configUploadNoSuccessTryCount<CONFIG_PROCESS_RESUME_COUNT:
self.parent.queue.addSetDevConfig()
self.configUploadNoSuccessTryCount+=1
else:
self.updater.addConfigUploadState("upload_config_"+str(hex(ord(self.configUploadActualCommand))),"FAIL")
if self.configUploadProcessCurrIndex<len(PATTERN_SET_CONFIG_FRAMES):
self.updater.setState("conf_upload_progress")
self.configUploadProcessCurrIndex+=1
self.parent.queue.addSetDevConfig()
self.configUploadNoSuccessTryCount=0
else:
if not self.updater is None:
self.updater.endConfigUpload()
if state.getRemoteMenuStatus():
self.reloadLang()
self.initMsgQueue()
self.configUploadProcessInProgress=False
def createEcoNetGetDevConfigFrame(self,sender,request):
if self.configDownloadProcessInProgress and self.configDownloadProcessCurrIndex<len(PATTERN_GET_CONFIG_FRAMES):
if not self.configPfcFile is None:
order_data=PATTERN_GET_CONFIG_FRAMES[self.configDownloadProcessCurrIndex]
order=order_data[0]
d=order
if len(order_data)>1:
index=1
while index<len(order_data):
d+=order_data[index]
index+=1
if order==FRAME_GET_CONFIG_BURNERS:
d+=chr(self.configDownloadProcessBurnerIndex)
frame=createEcoNetFrame(sender,d)
self.configDownloadProcessWaitForCommand=PATTERN_GET_CONFIG_FRAMES_ANS[self.configDownloadProcessCurrIndex][0]
return frame
else:
if not self.configPfcFile is None:
self.configPfcFile.endPfcFile(version_data=self.moduleAVersionData)
self.resetConfigDownloadParam()
def getNextDevConfigFrame(self):
self.configDownloadProcessCurrIndex+=1
self.parent.queue.addGetDevConfig()
self.configDownloadNoSuccessTryCount=0
def readConfigFrameDataSchema(self,sender):
msg=self.message[8:-2]
if len(msg)>5:
data_type=ord(msg[0])
params_data=msg[1:]
did=params_data[1:3]
pv=params_data[3]
sw_ver=[0,0]
if data_type==1:
self.configDownloadSchemaBurnersProfilesCount=ord(msg[5])
self.configPfcFile.addConfigSchemaDataSection(params_data,data_type,did,sw_ver,pv)
self.getNextDevConfigFrame()
def readConfigFrameDataCurrent(self,sender):
msg=self.message[8:-2]
if len(msg)>2:
read_count=ord(msg[0])
index=ord(msg[1])
did=ord(self.message[5])
pv=self.message[6]
params_values_data=msg[:2]
params_data=msg[2:]
index=0
for param in params_data:
if index%3==0:
params_values_data+=param
index+=1
sw_ver=[0,0]
self.configPfcFile.addConfigCurrentDataSection(params_values_data,did,sw_ver,pv,0,True)
self.getNextDevConfigFrame()
def readConfigFrameDataFabric(self,sender):
msg=self.message[8:-2]
did=ord(self.message[5])
pv=self.message[6]
cmd=self.message[7]
pfc_section_close=False
if(cmd==FRAME_GET_CONFIG_BURNERS_ANS and len(msg)<=1):
pfc_section_close=True
sw_ver=[0,0]
if cmd==FRAME_GET_CONFIG_COMMON_ANS:
data_size=len(msg)
params_count=data_size/3
values=msg[:params_count]
descrs=msg[params_count:]
self.configPfcFile.addConfigFabrDataSection(values,did,sw_ver,pv,0,FRAME_SET_CONFIG_COMMON_VALS,pfc_section_close)
self.configPfcFile.addConfigFabrDataSection(descrs,did,sw_ver,pv,0,FRAME_SET_CONFIG_COMMON,pfc_section_close)
elif cmd==FRAME_GET_CONFIG_TEXTS_ANS:
self.configPfcFile.addConfigFabrDataSection(msg,did,sw_ver,pv,0,FRAME_SET_CONFIG_TEXTS,pfc_section_close)
elif cmd==FRAME_GET_CONFIG_NOEDIT_ANS:
self.configPfcFile.addConfigFabrDataSection(msg,did,sw_ver,pv,0,FRAME_SET_CONFIG_NOEDIT,pfc_section_close)
elif cmd==FRAME_GET_CONFIG_BURNERS_ANS or(cmd==FRAME_GET_CONFIG_BURNERS_NOINDEX_ANS and self.configDownloadProcessBurnerIndex<self.configDownloadSchemaBurnersProfilesCount):
data=''
if len(msg)==0:
if self.lastConfUploadBurnerDataSize>0:
data=chr(self.configDownloadProcessBurnerIndex)+utils.toStrTab([0]*self.lastConfUploadBurnerDataSize)
else:
self.lastConfUploadBurnerDataSize=(len(msg)-1)
data=msg
self.configPfcFile.addConfigFabrDataSection(data,did,sw_ver,pv,0,FRAME_SET_CONFIG_BURNERS,pfc_section_close)
self.configDownloadProcessBurnerIndex+=1
if not pfc_section_close and self.configDownloadProcessBurnerIndex<256:
self.parent.queue.addGetDevConfig()
self.configDownloadNoSuccessTryCount=0
return
self.getNextDevConfigFrame()
def startSetConfigData(self):
if not self.updater is None and self.updater.hasConfigToUpload():
self.configUploadFabrData=self.updater.getFabrCurrUploadDataTable(pfc_file.PfcFile.PFC_SECTION_FABR_DATA)
self.configUploadCurrData=self.updater.getFabrCurrUploadDataTable(pfc_file.PfcFile.PFC_SECTION_CURR_DATA)
eeprom_frame=False
for frame in self.configUploadFabrData:
if frame[0]==FRAME_SET_CONFIG_EEPROM_CL:
eeprom_frame=True
break
if not eeprom_frame:
self.configUploadFabrData.append([FRAME_SET_CONFIG_EEPROM_CL,pfc_file.PfcFile.EEPROM_CLEAR_PASS])
self.configUploadProcessInProgress=True
self.configUploadProcessCurrIndex=0
self.updater.setState("conf_upload_progress")
self.parent.queue.addSetDevConfig()
def resetConfigUploadDataObj(self):
self.configPfcFile=None
self.configUploadProcessInProgress=False
self.configUploadProcessCurrIndex=0
self.configUploadProcessWaitForCommand=''
self.configUploadNoSuccessTryCount=0
self.configUploadCurrData=[]
self.configUploadFabrData=[]
self.configUploadCurrIndex=0
self.configUploadFabrIndex=0
self.configUploadActualCommand=''
self.lastConfUploadBurnerIndex=-1
self.lastConfUploadBurnerDataSize=0
def writeConfigFrameDataCurrFabric(self,sender):
cmd=self.message[7]
if cmd==FRAME_SET_CONFIG_EEPROM_CL_ANS:
time.sleep(5)
if self.configUploadProcessInProgress and self.configUploadProcessCurrIndex<len(PATTERN_SET_CONFIG_FRAMES):
upload_type=PATTERN_SET_CONFIG_FRAMES[self.configUploadProcessCurrIndex]
if upload_type==pfc_file.PfcFile.PFC_SECTION_FABR_DATA:
self.updater.addConfigUploadState("upload_config_"+str(hex(ord(cmd))),"OK")
self.configUploadFabrIndex+=1
if self.configUploadFabrIndex>=len(self.configUploadFabrData):
self.updater.setState("conf_upload_progress")
self.configUploadProcessCurrIndex+=1
if upload_type==pfc_file.PfcFile.PFC_SECTION_CURR_DATA:
couter_add=True
if cmd==FRAME_SET_CONFIG_CURRENT_EDIT_ANS:
msg=self.message[8:-2]
params_values_data=msg[:2]
params_data=msg[2:]
index=0
for param in params_data:
if index%3==0:
params_values_data+=param
index+=1
if couter_add:
self.updater.addConfigUploadState("upload_config_"+str(hex(ord(cmd))),"OK")
self.configUploadCurrIndex+=1
if self.configUploadCurrIndex>=len(self.configUploadCurrData):
self.updater.setState("conf_upload_progress")
self.configUploadProcessCurrIndex+=1
self.parent.queue.addSetDevConfig()
def createEcoNetSetDevConfigFrame(self,sender,request):
if self.configUploadProcessInProgress and self.configUploadProcessCurrIndex<len(PATTERN_SET_CONFIG_FRAMES):
upload_type=PATTERN_SET_CONFIG_FRAMES[self.configUploadProcessCurrIndex]
if not self.updater is None and self.updater.hasConfigToUpload():
if upload_type==pfc_file.PfcFile.PFC_SECTION_FABR_DATA:
if not self.configUploadFabrData is None and len(self.configUploadFabrData)>0 and self.configUploadFabrIndex<len(self.configUploadFabrData):
frame_data=self.configUploadFabrData[self.configUploadFabrIndex]
cmd=frame_data[0]
respcmd=getDeviceConfigRespCmd(cmd)
if not respcmd is None:
self.configUploadActualCommand=respcmd
data=frame_data[1]
if cmd==FRAME_SET_CONFIG_BURNERS:
if len(data)==0:
if self.lastConfUploadBurnerDataSize>0:
data=chr(self.lastConfUploadBurnerIndex+1)+utils.toStrTab([0]*self.lastConfUploadBurnerDataSize)
self.lastConfUploadBurnerIndex+=1
else:
self.lastConfUploadBurnerIndex=ord(data[0])
self.lastConfUploadBurnerDataSize=(len(data)-1)
if len(data)==0:
return
d=cmd+data
else:
return
else:
return
if upload_type==pfc_file.PfcFile.PFC_SECTION_CURR_DATA:
if not self.configUploadCurrData is None and len(self.configUploadCurrData)>0 and self.configUploadCurrIndex<len(self.configUploadCurrData):
frame_data=self.configUploadCurrData[self.configUploadCurrIndex]
cmd=frame_data[0]
respcmd=getDeviceConfigRespCmd(cmd)
if not respcmd is None:
self.configUploadActualCommand=respcmd
data=frame_data[1]
d=cmd+data
else:
return
else:
return
frame=createEcoNetFrame(sender,d)
return frame
else:
if not self.updater is None:
self.updater.endConfigUpload()
if state.getRemoteMenuStatus():
self.reloadLang()
self.configUploadProcessInProgress=False
def currentEditFrameResp(self,sender):
if self.configDownloadProcessInProgress:
self.readConfigFrameDataCurrent(sender)
elif self.configUploadProcessInProgress:
self.writeConfigFrameDataCurrFabric(sender)
def compatibleSNAFU(devID,pfiID,devSW,pfiSW):
if devID==ECOMAX_200_DEVID and pfiID in[ECOMAX_250R_DEVID,ECOMAX_250R_FL_DEVID,ECOMAX_250W_DEVID]:
logger.info("EcoMAX200 to EcoMAX250R/R_FL/W upgrade")
return True
if(devID==SPARK_820X_MODA_DEVID and pfiID==ECOMAX_800R_MODA_DEVID)or(devID==SPARK_820X_PANEL_DEVID and pfiID==ECOMAX_800R_PANEL_DEVID):
if((pfiSW&0xFF00)>>8)>93:
logger.info("Switch from SPARK 820X MODA to EcoMAX 800R MODA or from SPARK 820X panel to EcoMAX 800R panel")
return True
if(devID==ECOMAX_800R_MODA_DEVID and pfiID==SPARK_820X_MODA_DEVID)or(devID==ECOMAX_800R_PANEL_DEVID and pfiID==SPARK_820X_PANEL_DEVID):
if((devSW&0xFF00)>>8)>93:
logger.info("Switch from EcoMAX 800R MODA to SPARK 820X MODA or from EcoMAX 800R panel to SPARK 820X panel")
return True
# Created by pyminifier (https://github.com/liftoff/pyminifier)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment