cryptk / haomnilogic-local

A Home Assistant integration for Hayward OmniLogic/OmniHub pool controllers using the local UDP api
Apache License 2.0
19 stars 4 forks source link

"Failed to parse Telemetry" during configuration #71

Closed mmun closed 1 year ago

mmun commented 1 year ago

First of all, thank you for starting this project!

I am getting errors while adding the integration.

2023-07-21 19:46:28.204 ERROR (MainThread) [custom_components.omnilogic_local.config_flow] Unexpected exception: Failed to parse Telemetry: 10 validation errors for Telemetry
Chlorinator -> 0 -> @enable
field required (type=value_error.missing)
Chlorinator -> 1 -> @enable
field required (type=value_error.missing)
VirtualHeater -> 0 -> @SolarSetPoint
field required (type=value_error.missing)
VirtualHeater -> 0 -> @Mode
field required (type=value_error.missing)
VirtualHeater -> 0 -> @SilentMode
field required (type=value_error.missing)
VirtualHeater -> 0 -> @whyHeaterIsOn
field required (type=value_error.missing)
VirtualHeater -> 1 -> @SolarSetPoint
field required (type=value_error.missing)
VirtualHeater -> 1 -> @Mode
field required (type=value_error.missing)
VirtualHeater -> 1 -> @SilentMode
field required (type=value_error.missing)
VirtualHeater -> 1 -> @whyHeaterIsOn
field required (type=value_error.missing)
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/pyomnilogic_local/models/telemetry.py", line 238, in load_xml
return Telemetry.parse_obj(data["STATUS"])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pydantic/main.py", line 526, in parse_obj
return cls(**obj)
^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pydantic/main.py", line 341, in __init__
raise validation_error
pydantic.error_wrappers.ValidationError: 10 validation errors for Telemetry
Chlorinator -> 0 -> @enable
field required (type=value_error.missing)
Chlorinator -> 1 -> @enable
field required (type=value_error.missing)
VirtualHeater -> 0 -> @SolarSetPoint
field required (type=value_error.missing)
VirtualHeater -> 0 -> @Mode
field required (type=value_error.missing)
VirtualHeater -> 0 -> @SilentMode
field required (type=value_error.missing)
VirtualHeater -> 0 -> @whyHeaterIsOn
field required (type=value_error.missing)
VirtualHeater -> 1 -> @SolarSetPoint
field required (type=value_error.missing)
VirtualHeater -> 1 -> @Mode
field required (type=value_error.missing)
VirtualHeater -> 1 -> @SilentMode
field required (type=value_error.missing)
VirtualHeater -> 1 -> @whyHeaterIsOn
field required (type=value_error.missing)
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/config/custom_components/omnilogic_local/config_flow.py", line 105, in async_step_user
await validate_input(self.hass, user_input)
File "/config/custom_components/omnilogic_local/config_flow.py", line 51, in validate_input
telemetry = await omni.async_get_telemetry()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pyomnilogic_local/models/util.py", line 43, in wrapper
return pydantic_type.load_xml(resp_body)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pyomnilogic_local/models/telemetry.py", line 240, in load_xml
raise OmniParsingException(f"Failed to parse Telemetry: {exc}") from exc
pyomnilogic_local.exceptions.OmniParsingException: Failed to parse Telemetry: 10 validation errors for Telemetry
Chlorinator -> 0 -> @enable
field required (type=value_error.missing)
Chlorinator -> 1 -> @enable
field required (type=value_error.missing)
VirtualHeater -> 0 -> @SolarSetPoint
field required (type=value_error.missing)
VirtualHeater -> 0 -> @Mode
field required (type=value_error.missing)
VirtualHeater -> 0 -> @SilentMode
field required (type=value_error.missing)
VirtualHeater -> 0 -> @whyHeaterIsOn
field required (type=value_error.missing)
VirtualHeater -> 1 -> @SolarSetPoint
field required (type=value_error.missing)
VirtualHeater -> 1 -> @Mode
field required (type=value_error.missing)
VirtualHeater -> 1 -> @SilentMode
field required (type=value_error.missing)
VirtualHeater -> 1 -> @whyHeaterIsOn
field required (type=value_error.missing)

Here is the configuration I used:

image

I can confirm that the HomeAssistant container can reach the OmniLogic controller:

pi@raspberrypi:~ $ sudo docker exec -it HomeAssistant bash
3fb51e04b575:/config# ping 192.168.1.228
PING 192.168.1.228 (192.168.1.228): 56 data bytes
64 bytes from 192.168.1.228: seq=0 ttl=63 time=4.713 ms
64 bytes from 192.168.1.228: seq=1 ttl=63 time=4.157 ms
mmun commented 1 year ago

If I use your library directly via the python repl inside my Home Assistant container I'm able to confirm that it's able to connect and read the config correctly:

3fb51e04b575:/config# python -m asyncio
asyncio REPL 3.11.4 (main, Jun 22 2023, 23:15:05) [GCC 12.2.1 20220924] on linux
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
>>> from pyomnilogic_local.api import OmniLogicAPI
>>> omni_api = OmniLogicAPI('192.168.1.228', 10444, 10.0)
>>> omni_api
<pyomnilogic_local.api.OmniLogicAPI object at 0xf7135cf0>
>>> await omni_api.async_get_config()
MSPConfig(system=MSPSystem(omni_type=<OmniType.SYSTEM: 'System'>, vsp_speed_format='RPM', units='Standard'), backyard=MSPBackyard(system_id=0, name='Backyard', bow_id=None, omni_type=<OmniType.BACKYARD: 'Backyard'>, sensor=[MSPSensor(system_id=15, name='AirSensor', bow_id=None, omni_type=<OmniType.SENSOR: 'Sensor'>, type=<SensorType.AIR_TEMP: 'SENSOR_AIR_TEMP'>, units=<SensorUnits.FAHRENHEIT: 'UNITS_FAHRENHEIT'>)], bow=[MSPBoW(system_id=2, name='Pool', bow_id=2, omni_type=<OmniType.BOW: 'BodyOfWater'>, type=<BodyOfWaterType.POOL: 'BOW_POOL'>, filter=[MSPFilter(system_id=4, name='Filter Pump', bow_id=2, omni_type=<OmniType.FILTER: 'Filter'>, type=<FilterType.VARIABLE_SPEED: 'FMT_VARIABLE_SPEED_PUMP'>, max_percent=100, min_percent=18, max_rpm=3450, min_rpm=600, priming_enabled='yes', low_speed=18, medium_speed=50, high_speed=100)], relay=None, heater=MSPVirtualHeater(system_id=5, name=None, bow_id=2, omni_type=<OmniType.VIRT_HEATER: 'VirtualHeater'>, enabled='yes', set_point=87, solar_set_point=None, max_temp=104, min_temp=65, heater_equipment=[MSPHeaterEquip(system_id=6, name='Gas', bow_id=2, omni_type=<OmniType.HEATER_EQUIP: 'Heater-Equipment'>, type='PET_HEATER', heater_type=<HeaterType.GAS: 'HTR_GAS'>, enabled='yes', min_filter_speed=50, sensor_id=-1, supports_cooling=None)]), sensor=[MSPSensor(system_id=16, name='WaterSensor', bow_id=2, omni_type=<OmniType.SENSOR: 'Sensor'>, type=<SensorType.WATER_TEMP: 'SENSOR_WATER_TEMP'>, units=<SensorUnits.FAHRENHEIT: 'UNITS_FAHRENHEIT'>), MSPSensor(system_id=18, name='FlowSensor', bow_id=2, omni_type=<OmniType.SENSOR: 'Sensor'>, type=<SensorType.FLOW: 'SENSOR_FLOW'>, units=<SensorUnits.ACTIVE_INACTIVE: 'UNITS_ACTIVE_INACTIVE'>)], colorlogic_light=None, pump=[MSPPump(system_id=20, name='Suction', bow_id=2, omni_type=<OmniType.PUMP: 'Pump'>, type=<PumpType.VARIABLE_SPEED: 'PMP_VARIABLE_SPEED_PUMP'>, function=<PumpFunction.CLEANER_SUCTION: 'PMP_CLEANER_SUCTION'>, max_percent=100, min_percent=18, max_rpm=3450, min_rpm=600, priming_enabled='yes', low_speed=18, medium_speed=50, high_speed=100)], chlorinator=MSPChlorinator(system_id=7, name='Chlorinator', bow_id=2, omni_type=<OmniType.CHLORINATOR: 'Chlorinator'>, enabled='yes', timed_percent=50, superchlor_timeout=24, dispenser_type=<ChlorinatorDispenserType.SALT: 'SALT_DISPENSING'>, chlorinator_equipment=[MSPChlorinatorEquip(system_id=8, name='Chlorinator1', bow_id=2, omni_type=<OmniType.CHLORINATOR_EQUIP: 'Chlorinator-Equipment'>, enabled='yes')])), MSPBoW(system_id=3, name='Spa', bow_id=3, omni_type=<OmniType.BOW: 'BodyOfWater'>, type=<BodyOfWaterType.SPA: 'BOW_SPA'>, filter=[MSPFilter(system_id=10, name='Filter Pump', bow_id=3, omni_type=<OmniType.FILTER: 'Filter'>, type=<FilterType.VARIABLE_SPEED: 'FMT_VARIABLE_SPEED_PUMP'>, max_percent=100, min_percent=18, max_rpm=3450, min_rpm=600, priming_enabled='yes', low_speed=18, medium_speed=50, high_speed=100)], relay=None, heater=MSPVirtualHeater(system_id=11, name=None, bow_id=3, omni_type=<OmniType.VIRT_HEATER: 'VirtualHeater'>, enabled='no', set_point=92, solar_set_point=None, max_temp=104, min_temp=65, heater_equipment=[MSPHeaterEquip(system_id=12, name='Gas', bow_id=3, omni_type=<OmniType.HEATER_EQUIP: 'Heater-Equipment'>, type='PET_HEATER', heater_type=<HeaterType.GAS: 'HTR_GAS'>, enabled='yes', min_filter_speed=50, sensor_id=-1, supports_cooling=None)]), sensor=[MSPSensor(system_id=17, name='WaterSensor', bow_id=3, omni_type=<OmniType.SENSOR: 'Sensor'>, type=<SensorType.WATER_TEMP: 'SENSOR_WATER_TEMP'>, units=<SensorUnits.FAHRENHEIT: 'UNITS_FAHRENHEIT'>), MSPSensor(system_id=19, name='FlowSensor', bow_id=3, omni_type=<OmniType.SENSOR: 'Sensor'>, type=<SensorType.FLOW: 'SENSOR_FLOW'>, units=<SensorUnits.ACTIVE_INACTIVE: 'UNITS_ACTIVE_INACTIVE'>)], colorlogic_light=None, pump=None, chlorinator=MSPChlorinator(system_id=13, name='Chlorinator', bow_id=3, omni_type=<OmniType.CHLORINATOR: 'Chlorinator'>, enabled='yes', timed_percent=10, superchlor_timeout=24, dispenser_type=<ChlorinatorDispenserType.SALT: 'SALT_DISPENSING'>, chlorinator_equipment=[MSPChlorinatorEquip(system_id=14, name='Chlorinator1', bow_id=3, omni_type=<OmniType.CHLORINATOR_EQUIP: 'Chlorinator-Equipment'>, enabled='yes')]))], relay=None))
>>> print(await omni_api.async_get_telemetry(raw=True))
<?xml version="1.0" encoding="UTF-8" ?>
<STATUS version="1.5">
    <Backyard systemId="0" statusVersion="5" airTemp="98" state="1" />
    <BodyOfWater systemId="2" waterTemp="83" flow="1" />
    <Filter systemId="4" filterState="1" filterSpeed="62" valvePosition="1" whyFilterIsOn="11" fpOverride="0" reportedFilterSpeed="62" power="376" lastSpeed="62" />
    <VirtualHeater systemId="5" Current-Set-Point="87" enable="1" />
    <Heater systemId="6" heaterState="1" temp="65535" enable="1" priority="0" maintainFor="24" />
    <Chlorinator systemId="7" status="128" instantSaltLevel="2861" avgSaltLevel="3194" chlrAlert="0" chlrError="0" scMode="0" operatingState="2" Timed-Percent="50" operatingMode="1" />
    <Pump systemId="20" pumpState="0" pumpSpeed="0" lastSpeed="100" whyOn="0" />
    <BodyOfWater systemId="3" waterTemp="-1" flow="1" />
    <Filter systemId="10" filterState="0" filterSpeed="0" valvePosition="1" whyFilterIsOn="1" fpOverride="0" reportedFilterSpeed="100" power="1338" lastSpeed="100" />
    <VirtualHeater systemId="11" Current-Set-Point="92" enable="0" />
    <Heater systemId="12" heaterState="0" temp="65535" enable="1" priority="0" maintainFor="24" />
    <Chlorinator systemId="13" status="0" instantSaltLevel="0" avgSaltLevel="0" chlrAlert="0" chlrError="0" scMode="0" operatingState="1" Timed-Percent="10" operatingMode="1" />
    <Group systemId="25" groupState="0" />
</STATUS>
mmun commented 1 year ago

Comparing with https://github.com/cryptk/python-omnilogic-local/blob/6f960b9b52e51e914cc8d630e8e14686da22fad5/pyomnilogic_local/models/telemetry.py#L30 it seems I may be on an old firmware.

mmun commented 1 year ago

Upgrading the firmware resolved this issue but now I'm running into https://github.com/cryptk/haomnilogic-local/issues/62.