theOrakle/glentronics

Integration Does Not Update Wifi Connected/Disconnected Status

Closed this issue · 12 comments

Anyone else have issues with updating? For whatever reason my device falls off the wifi network every couple months. Home Assistant never really updates any status or changes anything. I do notice the lack of connectivity in the Pro Series Android App so presumably the API is reporting it's not communicating correctly.

The integration seemed to have worked when I set it up, but I'm not sure it has ever updated.

If I reload the integration in HA, it'll show Unknown for a minute for all entities but eventually updates again with incorrect data.

The integration does cloud polling so if the app has issues, so will the integration. No local connect - sorry. With that said, about a month ago I think they had cloud issues, I even opened a case... Simple resolution really, cause your module to trip. AKA, pull a plug, disconnect a battery, etc. It will re-register your device and your app should start working too, then restart the integration. Let me know if your app works and the integration doesn't, cause that may be an issue I can fix.

The integration does cloud polling so if the app has issues, so will the integration. No local connect - sorry. With that said, about a month ago I think they had cloud issues, I even opened a case... Simple resolution really, cause your module to trip. AKA, pull a plug, disconnect a battery, etc. It will re-register your device and your app should start working too, then restart the integration. Let me know if your app works and the integration doesn't, cause that may be an issue I can fix.

Yep, understood. The app is working fine though. Sorry if I wasn't clear. Here's an example. I just removed and re-added the integration:

Screenshot_20240206_203026
2024-02-06 20_30_56-Home Assistant - Settings – Home Assistant

In this scenario, the app is correct. If I reset the device, it'll come back online but it's too difficult to debug when everything is OK since the integration says everything is OK always.

I would expect the integration to report that the Wifi Connection is not connected, cloud connection or not.

So there are 2 issues here:

  1. Your wiFi Module is not connected - You need to fix that
  2. The integration is not representing the states correctly - I need a log snippet to see what is happening there. Can you send me a snippet of the logs during a reload of the integration?

To be honest - I didn't test the WiFi disconnect (cause it was a PITA to setup) and just took the status from the cloud API for fact. But I'm happy to help you work through it.

Another thought... Do you possibly have 2 sets of creds (username & passwords) that you are hitting the app/integration with? I can upload a python script to test/dump out the json from the cloud API. Are you comfortable running a python script?

So there are 2 issues here:

1. Your wiFi Module is not connected - You need to fix that

2. The integration is not representing the states correctly - I need a log snippet to see what is happening there.  Can you send me a snippet of the logs during a reload of the integration?

To be honest - I didn't test the WiFi disconnect (cause it was a PITA to setup) and just took the status from the cloud API for fact. But I'm happy to help you work through it.

Yep, I absolutely understand it's not connected. I left it that way on purpose to test the integration. My issue is that I haven't really seen any of the values update in Home Assistant. It pulls in all the "all clear" values (Dry, OK, etc) on initialization and that was it. Been using it for a few months and just never seen any updates so I was starting to question if it was still working. Understanding it's a backup pump and it might easily go months without updating but it's fallen off my Wifi a couple times now and I never really know until I pull up the native app manually. I had set up HA alerts to tell me and obviously that's not really working.

Here are the logs on integration setup:

2024-02-08 15:39:45.723 INFO (MainThread) [homeassistant.components.binary_sensor] Setting up glentronics.binary_sensor
2024-02-08 15:39:45.826 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new binary_sensor.glentronics entity: binary_sensor.phcc_2400_sump_pump_backup_alarm_status
2024-02-08 15:39:45.827 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new binary_sensor.glentronics entity: binary_sensor.phcc_2400_sump_pump_backup_high_water_detector_status
2024-02-08 15:39:45.827 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new binary_sensor.glentronics entity: binary_sensor.phcc_2400_sump_pump_backup_wifi_module_status
2024-02-08 15:39:45.828 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new binary_sensor.glentronics entity: binary_sensor.phcc_2400_sump_pump_backup_firmware_version
2024-02-08 15:39:45.829 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new binary_sensor.glentronics entity: binary_sensor.phcc_2400_sump_pump_backup_last_received_alarm_from_wifi_module

How often is it polling? More than comfortable testing something with Python but it sounds like the issue might be more HA related and not API related?

Another thought... Do you possibly have 2 sets of creds (username & passwords) that you are hitting the app/integration with? I can upload a python script to test/dump out the json from the cloud API. Are you comfortable running a python script?

Just the 1 account for 1 pump in 1 house.

EDIT: I looked at your source code and created a collection in Postman. The results I get back from the API endpoint RetrieveWifiModules for my device are below:

[
    {
        "FirstName": null,
        "LastName": null,
        "EmailAddressOne": <Redacted>,
        "EmailAddressTwo": <Redacted>,
        "EmailAddressThree": null,
        "MobileNumber": <Redacted>,
        "CountryID": 1,
        "CountryName": <Redacted>,
        "CountryList": null,
        "PhoneProviderID": 3,
        "PhoneProviderName": <Redacted>,
        "PhoneProviderList": null,
        "Location": "PHCC-2400 Sump Pump Backup",
        "Token": <Redacted>,
        "ReceiveNotifications": true,
        "AllowedFirmwareUpdate": true,
        "UsedAsHighWaterAlarm": true,
        "DateCreated": "2021-09-06T16:26:47.93",
        "Updatestatus": null,
        "ProxyID": <Redacted>,
        "MACAddress": <Redacted>,
        "IsActive": true,
        "StatusList": null,
        "StatusFields": null,
        "WifiModuleStatus": false,
        "TennantCode": null,
        "DeviceTypeID": 0,
        "DeviceTypeName": null,
        "TemperatureMessage": null,
        "HumidityMessage": null,
        "HumidityThresholdMinEnabled": false,
        "TemperatureUnit": null,
        "HumidityThresholdMaxEnabled": false,
        "TemperatureThresholdMinEnabled": false,
        "TemperatureThresholdMaxEnabled": false,
        "HumidityThresholdMax": 0.0,
        "HumidityThresholdMin": 0.0,
        "TemperatureThresholdMax": 0.0,
        "TemperatureThresholdMin": 0.0
    }
]

Using the ProxyID then gets me this after the RetrieveProxyStatus call:

...
    "StatusList": [
        {
            "StatusID": <Redacted>,
            "ProxyID": <Redacted>,
            "Proxy": null,
            "ControlUnitType": "AGM_2400",
            "SerialConnectionStatus": "Normal",
            "ErrorString": "System Is Operating",
            "NormallyOpenRemoteTerminal": "Open",
            "NormallyClosedRemoteTerminal": "Open",
            "WirelessModuleBatteryStatus": "No Battery",
            "WaterSensor": "",
            "Temperature": "",
            "Humidity": null,
            "StatusTypeID": 0,
            "FirmwareVersion": "1.06.01",
            "DateModified": "2023-12-30T02:40:41",
            "DateCreated": "2023-12-30T02:40:41",
            "Voltage": "System",
            "WarningLight": null
        }
    ],
    "StatusFields": [
        {
            "FieldLabel": "Alarm Status (USB)",
            "FieldValue": "Connection lost",
            "FieldDetailInfo": "",
            "FieldIcon": "http://www.glentronicsconnect.com/Content/Images/MobileAppImages/Exclamation.png",
            "FieldStatusOK": true,
            "IsWarning": true
        },
        {
            "FieldLabel": "High Water Detector Status",
            "FieldValue": "Connection lost",
            "FieldDetailInfo": "",
            "FieldIcon": "http://www.glentronicsconnect.com/Content/Images/MobileAppImages/Exclamation.png",
            "FieldStatusOK": true,
            "IsWarning": true
        },
        {
            "FieldLabel": "WiFi Module Status",
            "FieldValue": "Connection to Wi-Fi is lost",
            "FieldDetailInfo": "Check your internet connection and power to the WiFi Module.",
            "FieldIcon": "http://www.glentronicsconnect.com/Content/Images/MobileAppImages/Alarm.png",
            "FieldStatusOK": false,
            "IsWarning": false
        },
        {
            "FieldLabel": "Firmware Version (software is up to date)",
            "FieldValue": "1.06.01",
            "FieldDetailInfo": "",
            "FieldIcon": "",
            "FieldStatusOK": true,
            "IsWarning": false
        },
        {
            "FieldLabel": "Last Received Alarm from WiFi Module",
            "FieldValue": "12/30/2023 2:40:41 AM",
            "FieldDetailInfo": "",
            "FieldIcon": "",
            "FieldStatusOK": true,
            "IsWarning": false
        }
    ],
...

So with all of that, I think the API is returning the "FieldStatusOK": false correctly for the Wifi Module but the Integration isn't picking that up.

I know next to nothing about HA development so not sure what to do with this information.

EDIT 2:
It looks like attributes actually have the data I want, but I would suggest fixing state.

image

Dude - that is perfect - my script would have dumped the same thing...

It updates every 30 seconds.

Let's add some debug output. You obviously already found <HA_CONFIG>/custom_components/glentronics directory. In that directory add the following line at the end of the parse_results function in the binary_sensor.py file:
_LOGGER.error(f"{self.idx}-{state}")

Should be indented and look like:
image

I have a feeling that my (untested) if statement in that function has a flaw...

Restart home assistant.
Tail or refresh the logs and you should see something like:

2024-02-08 11:16:00.651 ERROR (MainThread) [custom_components.glentronics.const] 0-True
2024-02-08 11:16:00.663 ERROR (MainThread) [custom_components.glentronics.const] 2-True
2024-02-08 11:16:00.665 ERROR (MainThread) [custom_components.glentronics.const] 4-True
2024-02-08 11:16:00.667 ERROR (MainThread) [custom_components.glentronics.const] 1-True
2024-02-08 11:16:00.669 ERROR (MainThread) [custom_components.glentronics.const] 3-True

Getting closer:

2024-02-08 17:34:29.147 ERROR (MainThread) [custom_components.glentronics.const] 1-True
2024-02-08 17:34:29.134 ERROR (MainThread) [custom_components.glentronics.const] 2-False
2024-02-08 17:34:29.144 ERROR (MainThread) [custom_components.glentronics.const] 4-True
2024-02-08 17:34:29.147 ERROR (MainThread) [custom_components.glentronics.const] 0-True
2024-02-08 17:34:29.147 ERROR (MainThread) [custom_components.glentronics.const] 3-True

I've been playing around with the code exactly there and can't get state to change to off for the life of me. I'd expect this to work but I'm not a python dev:

    def parse_results(self,results):
        state = pydash.get(results,f"{self.idx}.FieldStatusOK")
        if bool(state) and not self.field.find("WiFi") == 0:
            self._state="off"
        elif self.field.find("WiFi") == 1 and not bool(state):
            self._state="off"
        else:
            self._state = "on"  
        self._attributes["Value"] = pydash.get(results,f"{self.idx}.FieldValue")
        self._attributes["Detail"] = pydash.get(results,f"{self.idx}.FieldDetailInfo")
        self._attributes["Warning"] = pydash.get(results,f"{self.idx}.IsWarning")
        _LOGGER.error(f"{self.idx}-{state}")   

EDIT: Changed the debug line to include the field just to sanity check

2024-02-08 17:41:29.255 ERROR (MainThread) [custom_components.glentronics.const] 3-Firmware Version-True
2024-02-08 17:41:29.260 ERROR (MainThread) [custom_components.glentronics.const] 1-High Water Detector Status-True
2024-02-08 17:41:29.271 ERROR (MainThread) [custom_components.glentronics.const] 4-Last Received Alarm from WiFi Module-True
2024-02-08 17:41:29.274 ERROR (MainThread) [custom_components.glentronics.const] 0-Alarm Status-True
2024-02-08 17:41:29.275 ERROR (MainThread) [custom_components.glentronics.const] 2-WiFi Module Status-False

EDIT2: I don't think it likes the find() call. If I hardcode to self.idx == 2 it seems to report state correctly.

    def parse_results(self,results):
        state = pydash.get(results,f"{self.idx}.FieldStatusOK")
        if bool(state) and not self.field.find("WiFi") == 0:
            self._state="off"
        else:
            self._state = "on"
        if self.idx == 2: # WiFi Module Status
            _LOGGER.error(f"Inside Wifi Module Status")
            if bool(state):
                self._state = "on"
            else:
                self._state = "off"          
        self._attributes["Value"] = pydash.get(results,f"{self.idx}.FieldValue")
        self._attributes["Detail"] = pydash.get(results,f"{self.idx}.FieldDetailInfo")
        self._attributes["Warning"] = pydash.get(results,f"{self.idx}.IsWarning")  

image

add this:
_LOGGER.error(f"{self.field.find("WiFi")}")

See if this does it for you:

    def parse_results(self,results):
        state = pydash.get(results,f"{self.idx}.FieldStatusOK")
        if bool(state):
            if not self.field.find("WiFi") == 0:
                self._state = "off"
            else:
                self._state = "on"
        else:
            self._state = "off"
        self._attributes["Value"] = pydash.get(results,f"{self.idx}.FieldValue")
        self._attributes["Detail"] = pydash.get(results,f"{self.idx}.FieldDetailInfo")
        self._attributes["Warning"] = pydash.get(results,f"{self.idx}.IsWarning")

See if this does it for you:

    def parse_results(self,results):
        state = pydash.get(results,f"{self.idx}.FieldStatusOK")
        if bool(state):
            if not self.field.find("WiFi") == 0:
                self._state = "off"
            else:
                self._state = "on"
        else:
            self._state = "off"
        self._attributes["Value"] = pydash.get(results,f"{self.idx}.FieldValue")
        self._attributes["Detail"] = pydash.get(results,f"{self.idx}.FieldDetailInfo")
        self._attributes["Warning"] = pydash.get(results,f"{self.idx}.IsWarning")

This works 👍

I created a new release 0.1.4.

You can update via HACS:
image

Close if you are happy - thanks for helping me debug.

Thanks!