Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Help Needed] Air Handler CFM Setpoint support #110

Closed
PeteRager opened this issue Dec 4, 2021 · 14 comments · Fixed by #192
Closed

[Help Needed] Air Handler CFM Setpoint support #110

PeteRager opened this issue Dec 4, 2021 · 14 comments · Fixed by #192
Labels
enhancement New feature or request

Comments

@PeteRager
Copy link
Owner

There are systems that have variable speed air handlers. So for example, when the fan is on, there is a system setting to specify the CFM the fan should output. This enhancement would expose this setting and allow it to be set.

@PeteRager PeteRager added the enhancement New feature or request label Dec 4, 2021
@rugene76
Copy link

rugene76 commented Dec 9, 2021

yes please.
I've got a 1 year old 4 zone dual furnace system with a variable speed HP and air handler - so, while not essential, knowing the blower speed would be interesting. Currently I track power usage using Emporia Energy's sensors and can directly measure blower and HP power. A direct measurement of CFM from the S30 might be more useful for alerting purposes.

thanks!

@PeteRager
Copy link
Owner Author

There is an attribute on the climate entity called “demand”, this is the CFM that is active on the zone. Take a look at that, let me know if you get data. You can create a template sensor to pull the attribute out into its own sensor.

@dcj
Copy link

dcj commented Dec 21, 2021

I am currently running V 0.0.5 and what I currently see is:
demand: 0
I will update to the latest release (seems like generally a good idea), and see if I get any data here.

@PeteRager
Copy link
Owner Author

Sounds good. Let me know what you see. You should only see Demand = 0 when the zone is not calling for heating or cooling. If it’s actively heating or cooling it should have a non zero number.

@dcj
Copy link

dcj commented Dec 21, 2021

OK, I made it through the update to v0.1.3a, see #119

Seems like this is working, here is what I see:

2021-12-21 15:04:01 DEBUG (MainThread) [lennoxs30api.s30api_async] processMessage complete lennox_zone id [1] dirty [True] dirtyList [['demand']]
                            "demand": 0,
                            "demand": 36.5,
                            "demand": 0,
                            "demand": 0,
                            "demand": 36.5,
                            "demand": 0,
                            "demand": 0,
                            "demand": 0,
                            "demand": 36.5,
                            "demand": 0,
                            "demand": 0,
                            "demand": 36.5,
2021-12-21 15:05:11 DEBUG (MainThread) [lennoxs30api.s30api_async] update_attr: zone Id [0] attr [demand] value [36.5]
2021-12-21 15:05:11 DEBUG (MainThread) [lennoxs30api.s30api_async] processMessage complete lennox_zone id [0] dirty [True] dirtyList [['tempOperation', 'demand']]
                            "demand": 36.5,
                            "demand": 36.5,
                            "demand": 0,
                            "demand": 36.5,
                            "demand": 0,
                            "demand": 36.5,
                            "demand": 36.5,
                            "demand": 0,
                            "demand": 36.5,
                            "demand": 36.5,
                            "demand": 0,
                            "demand": 36.5,
                            "demand": 0,
2021-12-21 15:08:11 DEBUG (MainThread) [lennoxs30api.s30api_async] update_attr: zone Id [1] attr [demand] value [0]
2021-12-21 15:08:11 DEBUG (MainThread) [lennoxs30api.s30api_async] processMessage complete lennox_zone id [1] dirty [True] dirtyList [['tempOperation', 'demand']]
                            "demand": 36.5,
                            "demand": 0,
                            "demand": 0,
                            "demand": 0,
                            "demand": 0,```

@PeteRager
Copy link
Owner Author

This should be possible to do, however I cannot determine the commands that are sent from the dealer control panel within the S30 thermostat.

@PeteRager PeteRager changed the title Air Handler CFM Support - Up vote if you want this. [Help Needed] Air Handler CFM Setpoint support Jul 2, 2022
@HyperActiveJ
Copy link
Contributor

Pete is right,
It seems possible to do this.
image

The way we can add it to this intergration is

  1. Install the dealer app in a VM or PC based android development environment: https://play.google.com/store/apps/details?id=com.lennox.iC3.dealermobile.droid&hl=en&gl=US
  2. Use pcap or similar to capture the data between the app and the HVAC.
  3. Decrypt the data (its over HTPPS) - this is where i'm stuck, might need a proxy or something instead of pcap.
  4. Back out the commands being send to control the airflow.

@hufman did this perviously, if i undersatnd correctly. His work is where i found the local https info and decoded the diag data. He may be able to provide more insight.

https://github.com/hufman/lennox_lcc

@hufman
Copy link
Contributor

hufman commented Jul 29, 2022

To clarify, I merely did static reverse engineering of the dealer app, and then poked at the local api with curl, and didn't do any HTTPS interception. I would expect this data to be available through the zone status though, and my repo has a few scripts to help dump the data out and see what it looks like!

@PeteRager
Copy link
Owner Author

I like that idea of setting it up in android dev environment. Here’s what I’ve found / tried so far..

I’ve been able to trick the dealer app into connecting to my WIFI, I have an old WiFi router set in bridge mode connected into a PFSense gateway.

  1. setup a WiFi network called DIRECT-XY12-3456, connect iPad to it.
  2. The dealer app tries to connect to a hard coded IP addresses, one of them is 17.57.147.5
  3. I tried configuring a NAT to redirect this to the S30 IP address, this did not seem to work…so instead…
  4. configured the iPad http proxy to redirect to a BURP proxy on my PC, and then configured the Burp Proxy to redirect to the S30, this kind of worked, in that I could see the App calling the end point to retrieve messages but the S30 was returning a 400 because the app had not called the endpoint to setup the subscription. So it polls for messages for 15-30 seconds then gives up and declares that it is not connected.

The next thing to try is to manually setup that subscription, by calling the endpoint directly, and see if this makes the App happier.

@PeteRager
Copy link
Owner Author

I'm pretty sure this is the message to be sent:

{
    "systemControl":
    {
        "parameterUpdate" : 
        {
            "et" : "equipment type code",
            "pid" : "parameter id",
            "value": "str"
        }
    }
}

Where et is the equipment type code which we get in the equipment message, pid is the parameter id.

I found this list of et codes

      SYSTEM(0),
        FURNACE(16),
        AIR_HANDLER(17),
        AIR_CONDITIONER(18),
        HEAT_PUMP(19),
        ZONING_A(22),
        ZONING_B(23),
        PURE_AIR(28),
        COMFORT_SENSOR(64),
        THERMOSTAT(500),
        BASE(501),
        APPMAN(502),
        OS(503),
        WIFI(504),
        UNKNOWN(505),
        HOMEKIT(506),

You'd then want to send it using the same mechanism used to set the diagnostic level.

    async def set_diagnostic_level(self, level: int) -> None:
        level = int(level)
        _LOGGER.debug(f"set_diagnostic_level sysid [{self.sysId}] level[{level}]")
        if level not in (0, 1, 2):
            raise S30Exception(
                f"Invalid diagnostic level [{level}] valid value [0,1,2]",
                EC_BAD_PARAMETERS,
                1,
            )
        ## Put the parameterUpdate structure in here rather than diagControl
        data = '"Data":{"systemControl":{"diagControl":{"level":' + str(level) + "} } }"
        await self.api.publishMessageHelper(self.sysId, data)
        # The S30 does not send message when the systemControl parameters are update, but if we re-ask
        # for the systemControl subscription, it will send us the current data.
        await self.api.requestDataHelper(
            self.sysId,
            '"AdditionalParameters":{"JSONPath":"/systemControl"}',
        )

So I think it boils down to this (untested, unsyntax tested)

    async def set_eq_paramater(self, et:int, pid:int, value:str) -> None:
        command = {"systemControl": {"parameterUpdate": {"et": et, "pid" : str(pid), "value" : str(value)}}}
        await self.api.publish_message_helper_dict(self.sysId, command)

I'm not near my S30 for a while..

@PeteRager
Copy link
Owner Author

PeteRager commented Aug 14, 2022

Looks like this can work.

Command Sent:

2022-08-14 16:09:01,060 [MainThread  ] [DEBUG]  {
    "MessageType": "Command",
    "SenderID": "**redacted**",
    "MessageID": "00000000-0000-0000-0000-000000000003",
    "TargetID": "LCC",
    "Data": {
        "systemControl": {
            "parameterUpdate": {
                "et": 17,
                "pid": 19,
                "value": "565"
            }
        }
    }
}

Responses:

First, it looks like it is commissioning the change. When I make the change from the S30 panel I see a "System under Test" icon appear, I think this is driven by this status, though I never get an update that rsbusMode is "normal"

2022-08-14 16:09:08,642 [MainThread  ] [DEBUG]  {
    "messages": [
        {
            "MessageId": 0,
            "SenderID": "**redacted**",
            "TargetID": "ha_dev",
            "MessageType": "PropertyChange",
            "Data": {
                "system": {
                    "status": {
                        "rsbusMode": "commissioning"
                    },
                    "publisher": {
                        "publisherName": "lcc"
                    }
                }
            }
        }
    ]
}

Second it runs these tests?

2022-08-14 16:09:08,681 [MainThread  ] [DEBUG]  {
    "messages": [
        {
            "MessageId": 0,
            "SenderID": "**redacted**",
            "TargetID": "ha_dev",
            "MessageType": "PropertyChange",
            "Data": {
                "system": {
                    "test": {
                        "list": [
                            {
                                "test": {
                                    "tid": 0,
                                    "explanation": "Check Blower Operation",
                                    "name": "Blower"
                                },
                                "id": 0
                            },
                            {
                                "test": {
                                    "tid": 10,
                                    "explanation": "Check Min Rate Cooling Operation",
                                    "name": "Cooling - Minimum Rate"
                                },
                                "id": 1
                            },
                            {
                                "test": {
                                    "tid": 12,
                                    "explanation": "Check Max Rate Cooling Operation",
                                    "name": "Cooling - Maximum Rate"
                                },
                                "id": 2
                            }
                        ],
                        "szTest": 3
                    },
                    "publisher": {
                        "publisherName": "lcc"
                    }
                }
            }
        }
    ]
}

Then the parameter change gets reflected back in the configuration about 8 seconds after the command.

2022-08-14 16:09:08,812 [MainThread  ] [DEBUG]  {
    "messages": [
        {
            "MessageId": 0,
            "SenderID": "**redacted**",
            "TargetID": "ha_dev",
            "MessageType": "PropertyChange",
            "Data": {
                "equipments": [
                    {
                        "publisher": {
                            "publisherName": "lcc"
                        },
                        "equipment": {
                            "parameters": [
                                {
                                    "parameter": {
                                        "pid": 19,
                                        "enabled": true,
                                        "value": "565"
                                    },
                                    "id": 9
                                }
                            ],
                            "equipType": 17
                        },
                        "id": 2
                    }
                ]
            }
        }
    ]
}

@PeteRager PeteRager linked a pull request Aug 26, 2022 that will close this issue
@PeteRager
Copy link
Owner Author

@HyperActiveJ

I have figured out how to get the dealer app working and log the messages. I don't have a multizone system, so I don't get those controls and hence can't capture the messages to directly control the airflow.

It may require an iPad though, as I believe Android does not allow installing a BURP proxy cert? Anyways the steps are:

  1. Install the dealer app on iPad
  2. Create a new wifi network, called DIRECT-XY12-3456 (the dealer app looks specifically for this and won't work on networks with any other names), this network should bridge into the network with your PC and S30,
  3. Configure ipad to use that network
  4. Install Burp Proxy (free edition) on PC, start it, go to options. I configured it to run on port 8080, and opened this on the PC firewall for incoming.

burpsetup_a

Next, configure BURP proxy to route all traffic to the S30.

burpsetup

Turn BURP intercept off, otherwise it will pause on each request.

  1. On the iPAD configure the proxy for the DIRECT-Xy12-* WIFI network, to be BURP on the PC, go to the BURP ip address in Safari and download / install the certificate onto the iPad - BURP docs describe this well.

  2. Startup the dealer app, and you should see some traffic in BURP from it. For me it calls the message endpoint which fails since it never established a subscription. Don't know why, anyways in the URL you'll see the app_id it should be DCA_nnnnnn, where nnnnn is some unique id of the app. Copy this

  3. In an HA dev environment, configure the integration to connect to the S30 and use DCA_nnnnn as the app_id, verify the integration work.

  4. Stop HA, set a breakpoint here in the integrations init.py

breakpoint

  1. Run HA, it'll establish the subscription, and leave it at the breakpoint so it doesn't consume messages
  2. Restart the ipad app, it should connect and work. BURP should capture the messages.

@PeteRager
Copy link
Owner Author

I pointed the Lennox Tool at the API simulator that has zoning configured. Those controls just set the equipment parameters.

{"MessageType":"Command","SenderID":"dca_71824885284","MessageID":"00000000-0000-0000-0000-000000000009","TargetID":"LCC","AdditionalParameters":"\/systemControl","Data":{"systemControl":{"parameterUpdate":{"pid":272,"et":0,"value":"505"}}}}

@PeteRager
Copy link
Owner Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants