Skip to content

Commit

Permalink
Merge pull request #39 from claudegel/low-wifi
Browse files Browse the repository at this point in the history
Support for TH1400WF
  • Loading branch information
claudegel authored Nov 21, 2021
2 parents a21eeec + bc287d7 commit 54d4ebc
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 20 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ Automations require services to be able to send commande. Ex. light.turn_on. For
- neviweb130.set_sensor_alert to set all alert for water leak sensor, temperature, battery, leak, status and set action on valve
- neviweb130.set_valve_alert to set low battery alert status
- neviweb130.set_valve_temp_alert to set low temperature alert on sedna valve
- neviweb130.set_early_start to set early heating on/off for wifi thermostats
## Troubleshooting
if you see your device in the log but it do not apear in entity list you need to add the device model number in the code. Or you can send the model number to me so I can add it in the code.
Expand Down
2 changes: 1 addition & 1 deletion custom_components.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"neviweb130": {
"version": "0.1.4",
"version": "0.7.0",
"local_location": "/custom_components/neviweb130/__init__.py",
"remote_location": "https://github.com/claudegel/sinope-130/tree/master/custom_components/__init__.py",
"visit_repo": "https://github.com/claudegel/sinope-130",
Expand Down
9 changes: 8 additions & 1 deletion custom_components/neviweb130/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@
ATTR_MOTOR_TARGET,
ATTR_FLOOR_AIR_LIMIT,
ATTR_SIGNATURE,
ATTR_EARLY_START,
)

VERSION = '0.6.2'
VERSION = '0.7.0'

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -357,6 +358,12 @@ def set_floor_air_limit(self, device_id, status, temp):
_LOGGER.debug("floorairlimit.data = %s", data)
self.set_device_attributes(device_id, data)

def set_early_start(self, device_id, start):
"""Set early start on/off for wifi thermostats."""
data = {ATTR_EARLY_START: start}
_LOGGER.debug("early_start.data = %s", data)
self.set_device_attributes(device_id, data)

def set_setpoint_min(self, device_id, temp):
"""Set device setpoint minimum temperature."""
data = {ATTR_ROOM_SETPOINT_MIN: temp}
Expand Down
153 changes: 138 additions & 15 deletions custom_components/neviweb130/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
model 1510 = thermostat TH1123WF 3000W (wifi)
model 1510 = thermostat TH1124WF 4000W (wifi)
model 738 = thermostat TH1300WF 3600W and TH1310WF (wifi floor)
model ???? = thermostat TH1400WF low voltage (wifi)
model 739 = thermostat TH1400WF low voltage (wifi)
Support for Flextherm wifi thermostat
model 738 = Thermostat concerto connect FLP55 (wifi floor)
Expand Down Expand Up @@ -71,23 +71,32 @@
ATTR_ROOM_TEMPERATURE,
ATTR_ROOM_SETPOINT_MIN,
ATTR_ROOM_SETPOINT_MAX,
ATTR_ROOM_SETPOINT_AWAY,
ATTR_WATTAGE,
ATTR_GFCI_STATUS,
ATTR_FLOOR_MODE,
ATTR_OCCUPANCY,
ATTR_FLOOR_AUX,
ATTR_FLOOR_OUTPUT1,
ATTR_FLOOR_OUTPUT2,
ATTR_FLOOR_MAX,
ATTR_KEYPAD,
ATTR_BACKLIGHT,
ATTR_BACKLIGHT_AUTO_DIM,
ATTR_TIME,
ATTR_TEMP,
ATTR_WIFI_FLOOR_OUTPUT1,
ATTR_WIFI_WATTAGE,
ATTR_WIFI,
ATTR_WIFI_DISPLAY2,
ATTR_WIFI_KEYPAD,
ATTR_FLOOR_AIR_LIMIT,
ATTR_FLOOR_MAX,
ATTR_FLOOR_MIN,
ATTR_ROOM_TEMP_DISPLAY,
ATTR_EARLY_START,
ATTR_FLOOR_SENSOR,
ATTR_AUX_CYCLE,
ATTR_CYCLE,
ATTR_PUMP_PROTEC,
MODE_AUTO,
MODE_AUTO_BYPASS,
MODE_MANUAL,
Expand All @@ -101,6 +110,7 @@
SERVICE_SET_SETPOINT_MAX,
SERVICE_SET_SETPOINT_MIN,
SERVICE_SET_FLOOR_AIR_LIMIT,
SERVICE_SET_EARLY_START,
)

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -133,11 +143,12 @@
]

DEVICE_MODEL_LOW = [7372]
DEVICE_MODEL_LOW_WIFI = [739]
DEVICE_MODEL_FLOOR = [737]
DEVICE_MODEL_WIFI_FLOOR = [738]
DEVICE_MODEL_WIFI = [1510]
DEVICE_MODEL_HEAT = [1123, 1124, 7373]
IMPLEMENTED_DEVICE_MODEL = DEVICE_MODEL_HEAT + DEVICE_MODEL_FLOOR + DEVICE_MODEL_LOW + DEVICE_MODEL_WIFI_FLOOR + DEVICE_MODEL_WIFI
IMPLEMENTED_DEVICE_MODEL = DEVICE_MODEL_HEAT + DEVICE_MODEL_FLOOR + DEVICE_MODEL_LOW + DEVICE_MODEL_WIFI_FLOOR + DEVICE_MODEL_WIFI + DEVICE_MODEL_LOW_WIFI

SET_SECOND_DISPLAY_SCHEMA = vol.Schema(
{
Expand Down Expand Up @@ -203,6 +214,13 @@
}
)

SET_EARLY_START_SCHEMA = vol.Schema(
{
vol.Required(ATTR_ENTITY_ID): cv.entity_id,
vol.Required(ATTR_EARLY_START): cv.string,
}
)

async def async_setup_platform(
hass,
config,
Expand Down Expand Up @@ -310,6 +328,17 @@ def set_floor_air_limit_service(service):
thermostat.schedule_update_ha_state(True)
break

def set_early_start_service(service):
""" set early heating on/off for wifi thermostat """
entity_id = service.data[ATTR_ENTITY_ID]
value = {}
for thermostat in entities:
if thermostat.entity_id == entity_id:
value = {"id": thermostat.unique_id, "start": service.data[ATTR_EARLY_START]}
thermostat.set_early_start(value)
thermostat.schedule_update_ha_state(True)
break

hass.services.async_register(
DOMAIN,
SERVICE_SET_SECOND_DISPLAY,
Expand Down Expand Up @@ -366,6 +395,13 @@ def set_floor_air_limit_service(service):
schema=SET_FLOOR_AIR_LIMIT_SCHEMA,
)

hass.services.async_register(
DOMAIN,
SERVICE_SET_EARLY_START,
set_early_start_service,
schema=SET_EARLY_START_SCHEMA,
)

class Neviweb130Thermostat(ClimateEntity):
"""Implementation of a Neviweb thermostat."""

Expand All @@ -378,32 +414,49 @@ def __init__(self, data, device_info, name):
self._min_temp = 0
self._max_temp = 0
self._target_temp = None
self._target_temp_away = None
self._cur_temp = None
self._cur_temp_before = None
self._operation_mode = None
self._heat_level = 0
self._heat_source_type = None
self._gfci_status = None
self._floor_mode = None
self._floor_sensor_type = None
self._aux_heat = None
self._early_start = "off"
self._keypad = None
self._load2 = 0
self._load2_status = None
self._rssi = None
self._occupancy = None
self._wifi_display2 = None
self._backlight = None
self._floor_max = None
self._time_format = "24h"
self._floor_air_limit = None
self._floor_air_limit_status = None
self._floor_max = None
self._floor_max_status = "off"
self._floor_min = None
self._floor_min_status = "off"
self._temperature_format = TEMP_CELSIUS
self._temp_display_status = None
self._temp_display_value = None
self._cycle_length = None
self._aux_cycle_length = None
self._pump_protec_status = None
self._pump_protec_duration = None
self._pump_protec_freq = None
self._is_floor = device_info["signature"]["model"] in \
DEVICE_MODEL_FLOOR
self._is_wifi_floor = device_info["signature"]["model"] in \
DEVICE_MODEL_WIFI_FLOOR
self._is_wifi = device_info["signature"]["model"] in \
DEVICE_MODEL_WIFI_FLOOR or device_info["signature"]["model"] in DEVICE_MODEL_WIFI
DEVICE_MODEL_WIFI_FLOOR or device_info["signature"]["model"] in DEVICE_MODEL_WIFI or device_info["signature"]["model"] in DEVICE_MODEL_LOW_WIFI
self._is_low_voltage = device_info["signature"]["model"] in \
DEVICE_MODEL_LOW
self._is_low_wifi = device_info["signature"]["model"] in \
DEVICE_MODEL_LOW_WIFI
_LOGGER.debug("Setting up %s: %s", self._name, device_info)

def update(self):
Expand All @@ -412,21 +465,25 @@ def update(self):
else:
WATT_ATTRIBUTE = []
if self._is_floor or self._is_wifi_floor:
FLOOR_ATTRIBUTE = [ATTR_GFCI_STATUS, ATTR_FLOOR_MODE, ATTR_FLOOR_AUX, ATTR_FLOOR_OUTPUT2, ATTR_FLOOR_MAX, ATTR_FLOOR_AIR_LIMIT]
FLOOR_ATTRIBUTE = [ATTR_GFCI_STATUS, ATTR_FLOOR_MODE, ATTR_FLOOR_AUX, ATTR_FLOOR_OUTPUT2, ATTR_FLOOR_AIR_LIMIT, ATTR_FLOOR_SENSOR]
else:
FLOOR_ATTRIBUTE = []
if self._is_wifi_floor:
WIFI_FLOOR_ATTRIBUTE = [ATTR_WIFI_FLOOR_OUTPUT1]
WIFI_FLOOR_ATTRIBUTE = [ATTR_WIFI_FLOOR_OUTPUT1, ATTR_FLOOR_MAX, ATTR_FLOOR_MIM]
else:
WIFI_FLOOR_ATTRIBUTE = []
if self._is_wifi:
WIFI_ATTRIBUTE = [ATTR_WIFI_WATTAGE, ATTR_WIFI, ATTR_WIFI_KEYPAD, ATTR_WIFI_DISPLAY2, ATTR_SETPOINT_MODE, ATTR_OCCUPANCY]
else:
WIFI_ATTRIBUTE = [ATTR_KEYPAD, ATTR_BACKLIGHT]
if self._is_low_wifi:
LOW_WIFI_ATTRIBUTE = [ATTR_PUMP_PROTEC, ATTR_FLOOR_AIR_LIMIT, ATTR_ROOM_TEMP_DISPLAY, ATTR_FLOOR_MODE, ATTR_BACKLIGHT_AUTO_DIM, ATTR_EARLY_START, ATTR_FLOOR_SENSOR, ATTR_ROOM_SETPOINT_AWAY, ATTR_AUX_CYCLE, ATTR_CYCLE, ATTR_FLOOR_MAX, ATTR_FLOOR_MIN]
else:
LOW_WIFI_ATTRIBUTE = []
"""Get the latest data from Neviweb and update the state."""
start = time.time()
device_data = self._client.get_device_attributes(self._id,
UPDATE_ATTRIBUTES + FLOOR_ATTRIBUTE + WATT_ATTRIBUTE + WIFI_FLOOR_ATTRIBUTE + WIFI_ATTRIBUTE)
UPDATE_ATTRIBUTES + FLOOR_ATTRIBUTE + WATT_ATTRIBUTE + WIFI_FLOOR_ATTRIBUTE + WIFI_ATTRIBUTE + LOW_WIFI_ATTRIBUTE)
end = time.time()
elapsed = round(end - start, 3)
_LOGGER.debug("Updating %s (%s sec): %s",
Expand All @@ -451,21 +508,54 @@ def update(self):
self._wattage = device_data[ATTR_WATTAGE]
else:
self._heat_level = device_data[ATTR_OUTPUT_PERCENT_DISPLAY]["percent"]
self._operation_mode = device_data[ATTR_SETPOINT_MODE]
self._occupancy = device_data[ATTR_OCCUPANCY]
self._keypad = device_data[ATTR_WIFI_KEYPAD]
self._rssi = device_data[ATTR_WIFI]
self._wifi_display2 = device_data[ATTR_WIFI_DISPLAY2]
self._wattage = device_data[ATTR_WIFI_WATTAGE]
self._operation_mode = device_data[ATTR_SETPOINT_MODE]
self._occupancy = device_data[ATTR_OCCUPANCY]
if self._is_low_wifi:
self._heat_source_type = device_data[ATTR_OUTPUT_PERCENT_DISPLAY]["sourceType"]
self._temp_display_status = device_data[ATTR_ROOM_TEMP_DISPLAY]["status"]
self._temp_display_value = device_data[ATTR_ROOM_TEMP_DISPLAY]["value"]
self._floor_mode = device_data[ATTR_FLOOR_MODE]
self._backlight = device_data[ATTR_BACKLIGHT_AUTO_DIM]
self._early_start= device_data[ATTR_EARLY_START]
self._floor_sensor_type = device_data[ATTR_FLOOR_SENSOR]
self._target_temp_away = device_data[ATTR_ROOM_SETPOINT_AWAY]
self._aux_cycle_length = device_data[ATTR_AUX_CYCLE]
self._cycle_length = device_data[ATTR_CYCLE]
self._floor_max = device_data[ATTR_FLOOR_MAX]["value"]
self._floor_max_status = device_data[ATTR_FLOOR_MAX]["status"]
self._floor_min = device_data[ATTR_FLOOR_MIN]["value"]
self._floor_min_status = device_data[ATTR_FLOOR_MIN]["status"]
self._floor_air_limit = device_data[ATTR_FLOOR_AIR_LIMIT]["value"]
self._floor_air_limit_status = device_data[ATTR_FLOOR_AIR_LIMIT]["status"]
self._pump_protec_status = device_data[ATTR_PUMP_PROTEC]["status"]
self._pump_protec_duration = device_data[ATTR_PUMP_PROTEC]["duration"]
self._pump_protec_freq = device_data[ATTR_PUMP_PROTEC]["frequency"]
if ATTR_FLOOR_AIR_LIMIT in device_data:
self._floor_air_limit = device_data[ATTR_FLOOR_AIR_LIMIT]["value"]
self._floor_air_limit_status = device_data[ATTR_FLOOR_AIR_LIMIT]["status"]
if self._is_floor or self._is_wifi_floor:
self._gfci_status = device_data[ATTR_GFCI_STATUS]
self._floor_mode = device_data[ATTR_FLOOR_MODE]
self._aux_heat = device_data[ATTR_FLOOR_AUX]
self._floor_air_limit = device_data[ATTR_FLOOR_AIR_LIMIT]["value"]
self._floor_air_limit_status = device_data[ATTR_FLOOR_AIR_LIMIT]["status"]
self._floor_sensor_type = device_data[ATTR_FLOOR_SENSOR]
if ATTR_FLOOR_AIR_LIMIT in device_data:
self._floor_air_limit = device_data[ATTR_FLOOR_AIR_LIMIT]["value"]
self._floor_air_limit_status = device_data[ATTR_FLOOR_AIR_LIMIT]["status"]
if ATTR_FLOOR_MAX in device_data:
self._floor_max = device_data[ATTR_FLOOR_MAX]["value"]
self._floor_max_status = device_data[ATTR_FLOOR_MAX]["status"]
if ATTR_FLOOR_MIN in device_data:
self._floor_min = device_data[ATTR_FLOOR_MIN]["value"]
self._floor_min_status = device_data[ATTR_FLOOR_MIN]["status"]
if not self._is_wifi_floor:
self._load2_status = device_data[ATTR_FLOOR_OUTPUT2]["status"]
self._load2 = device_data[ATTR_FLOOR_OUTPUT2]["value"]
self._floor_max = device_data[ATTR_FLOOR_MAX]["value"]
else:
self._load2_status = None
self._load2 = device_data[ATTR_FLOOR_OUTPUT2]
Expand Down Expand Up @@ -503,17 +593,42 @@ def device_state_attributes(self):
data = {}
if not self._is_low_voltage:
data = {'wattage': self._wattage}
if self._is_low_wifi:
data.update({'source_type': self._heat_source_type,
'temp_display_status': self._temp_display_status,
'temp_display_value': self._temp_display_value,
'sensor_mode': self._floor_mode,
'early_start': self._early_start,
'floor_sensor_type': self._floor_sensor_type,
'load_watt': self._wattage,
'setpoint_away': self._target_temp_away,
'aux_cycle_length': self._aux_cycle_length,
'cycle_length': self._cycle_length,
'pump_protection_status': self._pump_protec_status,
'pump_protection_duration': self._pump_protec_duration,
'pump_protection_frequency': self._pump_protec_freq})
if self._is_floor or self._is_wifi_floor:
data.update({'gfci_status': self._gfci_status,
'sensor_mode': self._floor_mode,
'slave_heat': self._aux_heat,
'slave_status': self._load2_status,
'slave_load': self._load2,
'floor_setpoint_max': self._floor_max,
'floor_air_limit': self._floor_air_limit})
if self._is_wifi:
'floor_setpoint_low': self._floor_min,
'floor_air_limit': self._floor_air_limit,
'floor_sensor_type': self._floor_sensor_type,
'load_watt': self._wattage})
if self._is_wifi_floor or self._is_low_wifi:
data.update({'floor_limit_high': self._floor_max,
'floor_limit_high_status': self._floor_max_status,
'floor_limit_low': self._floor_min,
'floor_limit_low_status': self._floor_min_status,
'max_air_limit': self._floor_air_limit,
'max_air_limit_status': self._floor_air_limit_status})
if self._is_wifi and not self._is_low_wifi:
data.update({'second_display': self._wifi_display2,
'occupancy': self._occupancy})
'occupancy': self._occupancy,
'backlight': self._backlight})
data.update({'heat_level': self._heat_level,
'keypad': self._keypad,
'backlight': self._backlight,
Expand Down Expand Up @@ -691,6 +806,14 @@ def set_floor_air_limit(self, value):
entity, status, temp)
self._floor_air_limit = temp

def set_early_start(self, value):
""" set early heating on/off for wifi thermostat """
start = value["start"]
entity = value["id"]
self._client.set_early_start(
entity, start)
self._early_start = start

def set_hvac_mode(self, hvac_mode):
"""Set new hvac mode."""
if hvac_mode == HVAC_MODE_OFF:
Expand Down
13 changes: 11 additions & 2 deletions custom_components/neviweb130/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
ATTR_WATTAGE_OVERRIDE = "wattageOverride"
ATTR_SETPOINT_MODE = "setpointMode"
ATTR_ROOM_SETPOINT = "roomSetpoint"
ATTR_ROOM_SETPOINT_AWAY = "roomSetpointAway"
ATTR_ROOM_TEMPERATURE = "roomTemperature"
ATTR_OUTPUT_PERCENT_DISPLAY = "outputPercentDisplay"
ATTR_ROOM_SETPOINT_MIN = "roomSetpointMin"
Expand All @@ -24,10 +25,9 @@
ATTR_FLOOR_MODE = "airFloorMode"
ATTR_FLOOR_OUTPUT2 = "loadWattOutput2"
ATTR_FLOOR_AUX = "auxHeatConfig"
ATTR_FLOOR_MAX = "floorMaxAirTemperature"
ATTR_KEYPAD = "lockKeypad"
ATTR_OCCUPANCY = "occupancyMode"
ATTR_WIFI_FLOOR_OUTPUT1 = "loadWattOutput1" #status on/off, value=xx
ATTR_FLOOR_OUTPUT1 = "loadWattOutput1" #status on/off, value=xx
ATTR_LIGHT_WATTAGE = "loadWattOutput1" #status on/off, value=xx
ATTR_WIFI_WATTAGE = "loadWatt"
ATTR_WIFI = "wifiRssi"
Expand All @@ -36,6 +36,7 @@
ATTR_TIMER = "powerTimer"
ATTR_DRSTATUS = "drStatus"
ATTR_BACKLIGHT = "backlightAdaptive"
ATTR_BACKLIGHT_AUTO_DIM = "backlightAutoDim"
ATTR_LED_ON_INTENSITY = "statusLedOnIntensity"
ATTR_LED_OFF_INTENSITY = "statusLedOffIntensity"
ATTR_LED_ON_COLOR = "statusLedOnColor"
Expand All @@ -56,6 +57,14 @@
ATTR_CONF_CLOSURE = "cfgValveClosure"
ATTR_MOTOR_TARGET = "motorTargetPosition"
ATTR_FLOOR_AIR_LIMIT = "floorMaxAirTemperature"
ATTR_FLOOR_MAX = "floorLimitHigh"
ATTR_FLOOR_MIN = "floorLimitLow"
ATTR_ROOM_TEMP_DISPLAY = "roomTemperatureDisplay"
ATTR_EARLY_START = "earlyStartCfg"
ATTR_FLOOR_SENSOR = "floorSensorType"
ATTR_AUX_CYCLE = "auxCycleLength"
ATTR_CYCLE = "cycleLength"
ATTR_PUMP_PROTEC = "pumpProtection" #status on/off, duration, frequency

MODE_AUTO = "auto"
MODE_AUTO_BYPASS = "autoBypass"
Expand Down
Loading

0 comments on commit 54d4ebc

Please sign in to comment.