Last active
April 24, 2022 15:30
-
-
Save denpamusic/6375c2a57716dc42861350f0eebc1e68 to your computer and use it in GitHub Desktop.
ecomax.py file from official ecoNET 300 firmware
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/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