Skip to content

Commit

Permalink
Merge pull request #26 from claudegel/support-sedna
Browse files Browse the repository at this point in the history
Support sedna valve and sensor
  • Loading branch information
claudegel authored Jan 17, 2021
2 parents 8ebd513 + 40c9dfe commit 13e99ad
Show file tree
Hide file tree
Showing 7 changed files with 234 additions and 24 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ Here is a list of currently supported devices. Basically, it's everything that c
- Sinopé SP2610ZB in-wall outlet
- Sinopé SP2600ZB smart portable plug
- Water leak detector
- Sinopé VA4201WZ, sedna valve 1 inch
- Sinopé VA4200WZ, sedna valve 3/4 inch
- Sinopé VA4201WZ, VA4221WZ, sedna valve 1 inch
- Sinopé VA4200WZ, VA4220WZ, sedna valve 3/4 inch
- Sinopé WL4200, water leak detector
- Sinopé WL4200S, water leak detector with sensor
- Tank level monitor
Expand Down Expand Up @@ -107,6 +107,8 @@ Automations require services to be able to send commande. Ex. light.turn_on. For
- neviweb130.set_wattage to set wattageOverload for light devices.
- neviweb130.set_setpoint_min to set minimum setpoint temperature for thermostats.
- neviweb130.set_setpoint_max to set maximum setpoint temperature for thermostats.
- 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 allert status
## 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
28 changes: 25 additions & 3 deletions custom_components/neviweb130/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,15 @@
ATTR_LED_ON_COLOR,
ATTR_LED_OFF_COLOR,
ATTR_LIGHT_WATTAGE,
ATTR_LEAK_ALERT,
ATTR_BATT_ALERT,
ATTR_TEMP_ALERT,
ATTR_CONF_CLOSURE,
ATTR_MOTOR_TARGET,
ATTR_SIGNATURE,
)

VERSION = '0.3.0'
VERSION = '0.4.0'

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -269,8 +274,13 @@ def set_brightness(self, device_id, brightness):
def set_onOff(self, device_id, onoff):
"""Set device onOff state."""
data = {ATTR_ONOFF: onoff}
self.set_device_attributes(device_id, data)

self.set_device_attributes(device_id, data)

def set_valve_onOff(self, device_id, onoff):
"""Set sedna valve onOff state."""
data = {ATTR_MOTOR_TARGET: onoff}
self.set_device_attributes(device_id, data)

def set_mode(self, device_id, mode):
"""Set device operation mode."""
data = {ATTR_POWER_MODE: mode}
Expand Down Expand Up @@ -358,6 +368,18 @@ def set_wattage(self, device_id, watt):
_LOGGER.debug("wattage.data = %s", data)
self.set_device_attributes(device_id, data)

def set_valve_alert(self, device_id, batt):
"""Set Sedna valve battery alert on/off."""
data = {ATTR_BATT_ALERT: batt}
_LOGGER.debug("valve.data = %s", data)
self.set_device_attributes(device_id, data)

def set_sensor_alert(self, device_id, leak, batt, temp, close):
"""Set leak detector alert, battery, temperature, leak, Sedna valve closing."""
data = {ATTR_LEAK_ALERT: leak, ATTR_BATT_ALERT: batt, ATTR_TEMP_ALERT: temp, ATTR_CONF_CLOSURE: close}
_LOGGER.debug("leak.data = %s", data)
self.set_device_attributes(device_id, data)

def set_device_attributes(self, device_id, data):
try:
requests.put(DEVICE_DATA_URL + str(device_id) + "/attribute",
Expand Down
12 changes: 11 additions & 1 deletion custom_components/neviweb130/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
ATTR_BATTERY_VOLTAGE = "batteryVoltage"
ATTR_BATTERY_STATUS = "batteryStatus"
ATTR_LEVEL_STATUS = "tankLevelPercent"
ATTR_VALVE_STATUS = "valveAction"
ATTR_FLOOR_MODE = "airFloorMode"
ATTR_FLOOR_OUTPUT2 = "loadWattOutput2"
ATTR_FLOOR_AUX = "auxHeatConfig"
Expand All @@ -47,6 +46,15 @@
ATTR_BLUE = "blue"
ATTR_TIME = "timeFormat"
ATTR_TEMP = "temperatureFormat"
ATTR_MOTOR_POS = "motorPosition"
ATTR_TEMP_ALARM = "temperatureAlarmStatus"
ATTR_ROOM_TEMP_ALARM = "roomTemperatureAlarmStatus"
ATTR_VALVE_CLOSURE = "valveClosureSource" #source
ATTR_LEAK_ALERT = "alertWaterLeak"
ATTR_BATT_ALERT = "alertLowBatt"
ATTR_TEMP_ALERT = "alertLowTemp"
ATTR_CONF_CLOSURE = "cfgValveClosure"
ATTR_MOTOR_TARGET = "motorTargetPosition"

MODE_AUTO = "auto"
MODE_AUTO_BYPASS = "autoBypass"
Expand All @@ -69,3 +77,5 @@
SERVICE_SET_WATTAGE = "set_wattage"
SERVICE_SET_SETPOINT_MAX = "set_setpoint_max"
SERVICE_SET_SETPOINT_MIN = "set_setpoint_min"
SERVICE_SET_SENSOR_ALERT = "set_sensor_alert"
SERVICE_SET_VALVE_ALERT = "set_valve_alert"
1 change: 1 addition & 0 deletions custom_components/neviweb130/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from homeassistant.helpers.typing import HomeAssistantType

from datetime import timedelta
from homeassistant.helpers.event import track_time_interval
from .const import (
DOMAIN,
ATTR_INTENSITY,
Expand Down
99 changes: 92 additions & 7 deletions custom_components/neviweb130/sensor.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""
Support for Neviweb sensors connected via GT130 ZigBee.
model 5051 = WL4200ZB, water leak detector
model 5051 = WL4200S, water leak detector with sensor
model 5051 = WL4200ZB, and WL4200S water leak detector not connected to Sedna valve
model 5050 = WL4200ZB, and WL4200S, water leak detector connected to Sedna valve
model 4110 = LM4110-ZB, level monitor
For more details about this platform, please refer to the documentation at
https://www.sinopetech.com/en/support/#api
Expand All @@ -17,6 +17,7 @@

from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (
ATTR_ENTITY_ID,
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_TEMPERATURE,
TEMP_CELSIUS,
Expand All @@ -25,6 +26,18 @@
ATTR_VOLTAGE,
)

from homeassistant.helpers import (
config_validation as cv,
discovery,
service,
entity_platform,
entity_component,
entity_registry,
device_registry,
)

from homeassistant.helpers.typing import HomeAssistantType

from datetime import timedelta
from homeassistant.helpers.event import track_time_interval
from homeassistant.helpers.entity import Entity
Expand All @@ -36,8 +49,14 @@
ATTR_WATER_LEAK_STATUS,
ATTR_BATTERY_VOLTAGE,
ATTR_BATTERY_STATUS,
ATTR_ROOM_TEMP_ALARM,
ATTR_LEAK_ALERT,
ATTR_BATT_ALERT,
ATTR_TEMP_ALERT,
ATTR_CONF_CLOSURE,
MODE_OFF,
STATE_WATER_LEAK,
SERVICE_SET_SENSOR_ALERT,
)

_LOGGER = logging.getLogger(__name__)
Expand All @@ -48,13 +67,30 @@

IMPLEMENTED_TANK_MONITOR = [4110]
IMPLEMENTED_SENSOR_MODEL = [5051]
IMPLEMENTED_DEVICE_MODEL = IMPLEMENTED_SENSOR_MODEL + IMPLEMENTED_TANK_MONITOR
IMPLEMENTED_CONNECTED_SENSOR = [5050]
IMPLEMENTED_DEVICE_MODEL = IMPLEMENTED_SENSOR_MODEL + IMPLEMENTED_TANK_MONITOR + IMPLEMENTED_CONNECTED_SENSOR

SENSOR_TYPES = {
"leak": ["", None, None],
"level": ["%", None, None],
}

SET_SENSOR_ALERT_SCHEMA = vol.Schema(
{
vol.Required(ATTR_ENTITY_ID): cv.entity_id,
vol.Required(ATTR_LEAK_ALERT): vol.All(
vol.Coerce(int), vol.Range(min=0, max=1)
),
vol.Required(ATTR_BATT_ALERT): vol.All(
vol.Coerce(int), vol.Range(min=0, max=1)
),
vol.Required(ATTR_TEMP_ALERT): vol.All(
vol.Coerce(int), vol.Range(min=0, max=1)
),
vol.Required(ATTR_CONF_CLOSURE): cv.string,
}
)

async def async_setup_platform(
hass,
config,
Expand All @@ -70,14 +106,33 @@ async def async_setup_platform(
"model" in device_info["signature"] and \
device_info["signature"]["model"] in IMPLEMENTED_DEVICE_MODEL:
device_name = '{} {}'.format(DEFAULT_NAME, device_info["name"])
if device_info["signature"]["model"] in IMPLEMENTED_SENSOR_MODEL:
if device_info["signature"]["model"] in IMPLEMENTED_SENSOR_MODEL \
or device_info["signature"]["model"] in IMPLEMENTED_CONNECTED_SENSOR:
device_type = "leak"
elif device_info["signature"]["model"] in IMPLEMENTED_TANK_MONITOR:
device_type = "level"
entities.append(Neviweb130Sensor(data, device_info, device_name, device_type))

async_add_entities(entities, True)

def set_sensor_alert_service(service):
""" Set different alert and action for water leak sensor """
entity_id = service.data[ATTR_ENTITY_ID]
value = {}
for sensor in entities:
if sensor.entity_id == entity_id:
value = {"id": sensor.unique_id, "leak": service.data[ATTR_LEAK_ALERT], "temp": service.data[ATTR_TEMP_ALERT], "batt": service.data[ATTR_BATT_ALERT], "close": service.data[ATTR_CONF_CLOSURE]}
sensor.set_sensor_alert(value)
sensor.schedule_update_ha_state(True)
break

hass.services.async_register(
DOMAIN,
SERVICE_SET_SENSOR_ALERT,
set_sensor_alert_service,
schema=SET_SENSOR_ALERT_SCHEMA,
)

def voltage_to_percentage(voltage):
"""Convert voltage level from absolute 0..3.25 to percentage."""
return int((voltage * 100.0) / 3.25)
Expand All @@ -95,19 +150,26 @@ def __init__(self, data, device_info, name, device_type):
self._leak_status = None
self._battery_voltage = None
self._battery_status = None
self._temp_status = None
self._is_monitor = device_info["signature"]["model"] in \
IMPLEMENTED_TANK_MONITOR
self._is_leak = device_info["signature"]["model"] in \
IMPLEMENTED_SENSOR_MODEL
IMPLEMENTED_SENSOR_MODEL or device_info["signature"]["model"] in IMPLEMENTED_CONNECTED_SENSOR
self._is_connected = device_info["signature"]["model"] in \
IMPLEMENTED_CONNECTED_SENSOR
self._level_status = None
self._leak_status = None
self._leak_alert = None
self._temp_alert = None
self._battery_alert = None
self._closure_action = None
_LOGGER.debug("Setting up %s: %s", self._name, device_info)

def update(self):
if self._is_monitor:
MONITOR_ATTRIBUTE = [ATTR_LEVEL_STATUS]
else:
MONITOR_ATTRIBUTE = [ATTR_WATER_LEAK_STATUS, ATTR_ROOM_TEMPERATURE]
MONITOR_ATTRIBUTE = [ATTR_WATER_LEAK_STATUS, ATTR_ROOM_TEMPERATURE, ATTR_ROOM_TEMP_ALARM]
"""Get the latest data from Neviweb and update the state."""
start = time.time()
device_data = self._client.get_device_attributes(self._id,
Expand All @@ -123,6 +185,8 @@ def update(self):
self._leak_status = STATE_WATER_LEAK if \
device_data[ATTR_WATER_LEAK_STATUS] == STATE_WATER_LEAK else "ok"
self._cur_temp = device_data[ATTR_ROOM_TEMPERATURE]
if self._is_connected:
self._temp_status = device_data[ATTR_ROOM_TEMP_ALARM]
else:
self._level_status = device_data[ATTR_LEVEL_STATUS]
self._battery_voltage = device_data[ATTR_BATTERY_VOLTAGE]
Expand Down Expand Up @@ -190,7 +254,14 @@ def device_state_attributes(self):
data = {'Level': self._level_status}
elif self._is_leak:
data = {'Leak_status': self._leak_status,
'Temperature': self._cur_temp}
'Temperature': self._cur_temp,
'leak_alert': self._leak_alert,
}
if self._is_connected:
data.update({'Temp_alarm': self._temp_status,
'Temperature_alert': self._temp_alert,
'Battery_alert': self._battery_alert,
'Closure_action': self._closure_action})
data.update({'Battery': voltage_to_percentage(self._battery_voltage),
'Battery status': self._battery_status,
'Id': self._id})
Expand All @@ -213,3 +284,17 @@ def state(self):
return self._level_status
elif self._is_leak:
return self._leak_status

def set_sensor_alert(self, value):
""" Set water leak sensor alert and action """
leak = value["leak"]
batt = value["batt"]
temp = value["temp"]
close = value["close"]
entity = value["id"]
self._client.set_sensor_alert(
entity, leak, batt, temp, close)
self._leak_alert = "true" if leak == 1 else "false"
self._temp_alert = "true" if temp == 1 else "false"
self._battery_alert = "true" if batt == 1 else "false"
self._closure_action = close
29 changes: 29 additions & 0 deletions custom_components/neviweb130/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,32 @@ set_setpoint_min:
roomSetpointMin:
description: Minimum setpoint temperature to set.
example: 10

set_sensor_alert:
description: Set water leak sensor alert service. For leak sensor connected to Sedna valve, all four alert can be set. For leak sensor not connected to Sedna valve only the battery alert is set.
fields:
entity_id:
description: Name(s) of neviweb130 water leak sensor.
example: "sensor.neviweb130_sensor_water_heater"
alertWaterLeak:
description: Set to 1, send alert or 0, do nothing.
example: 1
alertLowBatt:
description: Set to 1, send alert or 0, do nothing.
example: 1
alertLowTemp:
description: Set to 1, send alert or 0, do nothing.
example: 1
cfgValveClosure:
description: Set to «on», close the valve when leak is detected or «off», do nothing. Leak sensor not connected to Sedna valve will not close the valve on leak detection.
example: "on"

set_valve_alert:
description: Set water valve alert service.
fields:
entity_id:
description: Name(s) of neviweb130 water leak sensor.
example: "switch.neviweb130_switch_valve"
alertLowBatt:
description: Set to «true», send alert or «false», do nothing.
example: "true"
Loading

0 comments on commit 13e99ad

Please sign in to comment.