nebulous / infinitude

Open control of Carrier/Bryant thermostats
MIT License
224 stars 50 forks source link

Heat source #166

Closed lukazareba closed 1 year ago

lukazareba commented 1 year ago

Hi

Is avaible any method to change heat source in HA? If not could you pls add?

thekev commented 1 year ago

I can't decipher how the "api" 😆 would do this. By reverse-engineering the UI, I came up with:

curl -s http://infinitude/systems.json | jq '.system[0].config[0].heatsource[0] = "odu only"' | curl http://infinitude/systems/infinitude -d @-

To force it to heat pump only. For aux/gas heat use "idu only" and for system in control, "system".

nebulous commented 1 year ago

The method @thekev mentions will work and if you're willing to the mutations in jq it's the most flexible. However the (apparently laughable) api will do the json merge for you if you'd rather not do it yourself. I think the equivalent api call would be /api/config/?heatsource=odu only (and yes, mutations should not be allowed on GET - but Infinitude supports that since many automation controllers are unable to generate POST/PUT)

https://github.com/nebulous/infinitude/wiki/Infinitude-API-calls

thekev commented 1 year ago

(apparently laughable) api

I tried posting json fragments to /api/config and it temporarily corrupted the xml config. The code path for /api/*variable_path is quite generic, lacks validation (curl 'http://infinitude/api/config' -d heatsource=hamster), and documentation is limited. My 😆 wasn't meant to be personal. I apologize for my choice of words, and do appreciate your efforts.

I was able to modify the heatsource as you described, using both post and get. Thanks for your assistance.

thekev commented 1 year ago

So turns out heat source isn’t actually updating on the thermostat via /api/config?heatsource. I can see in the UI and /api/config JSON that the value is being changed, but the thermostat stays the same. However, if I set it in the UI, the thermostat does update. My ugly curl|jq|curl mutation above also is effective.

An example: curl 'http://localhost:3001/api/config?heatsource=odu%20only'. @nebulous How can I help debug this? (I used to write Perl, but it’s been 10 years or so).

nebulous commented 1 year ago

Yeah, that’s because the changed flag isn’t being set on GET. If you use PUT or POST it will be, or if you change anything else in the stat to force a change event, or if I change the code to stop disallowing mutations on GET or to have a flag to force a change cycle. Another contributor made the change to disallow GET mutations, which is the more correct behavior, but sometimes one just wants to bend the rules to getThingsDone. I’m open to hearing preferences in this regard.

On Mar 11, 2023, at 12:55 AM, Kevin Blackham @.***> wrote:

So turns out heat source isn’t actually updating on the thermostat via /api/config?heatsource. I can see in the UI and /api/config JSON that the value is being changed, but the thermostat stays the same. However, if I set it in the UI, the thermostat does update. My ugly curl|jq|curl mutation above also is effective.

An example: curl 'http://localhost:3001/api/config?heatsource=odu%20only'. @nebulous https://github.com/nebulous How can I help debug this? (I used to write Perl, but it’s been 10 years or so).

— Reply to this email directly, view it on GitHub https://github.com/nebulous/infinitude/issues/166#issuecomment-1464835748, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABLKZWGCTEMZLMFO3IOWNTW3QHTTANCNFSM6AAAAAAVJJHCYA. You are receiving this because you were mentioned.

thekev commented 1 year ago

I thought you just implied mutations are allowed on GET, even if it's bad form? So, they are accepted into local state, but don't work for updating the thermostat document? I was going down the path of POST because it's more correct, but my HA controller is easier to implement with GET. Confirmed with curl that POST will update the thermostat. I'll go have an argument with OpenHAB about doing a proper POST.

thekev commented 1 year ago

I'll go have an argument with OpenHAB about doing a proper POST.

Simply changing the method to POST is fully effective while still using the query string. A configuration snippet:

Thing http:url:hvacbeds "HVAC Beds" [ baseURL="http://127.0.0.1:3002/api", refresh=5, commandMethod="POST" ] {
    Channels:
        Type string : heatsource [ stateExtension="/config", stateTransformation="JSONPATH:$.data.heatsource", commandExtension="/config?heatsource=%2$s" ]
}

A change command sent and captured with tcpdump:

POST /api/config?heatsource=system HTTP/1.1
Accept-Encoding: gzip
User-Agent: Jetty/9.4.46.v20220331
Host: 127.0.0.1:3002
Content-Type: text/plain;charset=UTF-8
Content-Length: 6

system

I tried convincing it to use application/x-www-form-urlencoded instead of the query string, and supplying form data per typical - which Mojolicious accepts, but OpenHAB doesn't want to do that. It only allows application/json application/xml text/html text/plain or text/xml.

It would be excellent if I could post json fragments as payload and have that get merged in the same way as query/form does.

nebulous commented 1 year ago

I thought you just implied mutations are allowed on GET, even if it's bad form?

yep. I did imply that and I was wrong, because despite it "working" to mutate the document in Infinitude, we intentionally do not set the change flag unless the http verb is POST or PUT. So you'll be able to see the change until the next refresh cycle when it will revert back. As you discovered subsequently however, it plays pretty fast and loose with the rules of rest(and http for that matter) by merging query and body parameters. What's your opinion on how it should behave on the spectrum of convenient-wrongness to inconvenient-correctness? Some ideas

thekev commented 1 year ago
  • /api/config?heatsource=system&changes=true

This makes sense. Needs documentation. Probably simplest to implement.

  • /api/config?heatsource=system automatically set changes=true like we did before a0c3b7a but with change detection

I like this best. I think changes=true should also be permitted, and then just skip the change detection function.

  • what we have now

It's sufficient. Just need to find the right incantation.

  • /api/config force correct behavior with formdata containing heatsource=system and disallow query parameters

I wouldn't favor being strict on the verbs, for reasons that sometimes it's the only option. I like having the query string or the form data be interchangeable, for the same reason.

  • PUT/api/config with body containing json to merge

This seems like the wrong verb for a partial change.

  • POST /api/config with body containing json to replace

I think this makes sense, and fits into my system with a small javascript transform to format the json. Use the Content-type to determine if it's form or json data.

What about POST and GET at /api/config/{key}? I think this is more RESTy. Example:

POST /api/config/heatsource HTTP/1.1
Content-Type: text/plain;charset=UTF-8
Content-Length: 6

system

Not sure if that fits nicely into the data model, or how flat that map is, but it’s the best for simple integrations. What are your thoughts?

nebulous commented 1 year ago

ok, modified to accept a set_changes flag to force a change cycle which will be set automatically if a value is changed.

lukazareba commented 1 year ago

Hi

I am reading and reading your posts and I don't understand. I see that there is a possibility to change the heating source but I don't know how to do it in HA. Could one of you please explain it to me. Please help me a lot

nebulous commented 1 year ago

@lukazareba Changing the heating source is something that can only be done via Infinitude's API. MizterB's Infinitude HA integration doesn't expose the heat source mutating functionality as far as I'm aware. So if you want to have HA change the heat source you'll need to write a script to set the source and call it via the command line integration, or use the REST switch integration, or possibly other integrations under the REST/HTTP HA ubbrella.

lukazareba commented 1 year ago

@nebulous

Thanks for the info, I guessed there was no built-in function. Could you help me in writing a script that would call the rest function in HA?

lukazareba commented 1 year ago

I tried calling "/api/config/?heatsource=odu only" and "/api/config/?heatsource=idu only". Entries in the XML file changed, but not on the thermostat. That's why all my attempts failed. So what am I doing wrong?

thekev commented 1 year ago

@lukazareba if you're using GET for that, the commit referenced above added a set_changes=1 you might want to add to the query string. It also appears to have added change detection, so maybe you just need to be on the latest code?

lukazareba commented 1 year ago

@thekev I tried using the browser only. I typed in http://192.168.0.86:3000/api/config/?heatsource=odu only and other than the information from http://192.168.0.86:3000/api/config nothing changed on the thermostat. So please help me how to change it in HA using a script or something else.

image

thekev commented 1 year ago

@thekev I tried using the browser only. I typed in http://192.168.0.86:3000/api/config/?heatsource=odu only and other than the information from http://192.168.0.86:3000/api/config nothing changed on the thermostat. So please help me how to change it in HA using a script or something else.

Since you’re using the GET method in this case, try adding set_changes=1 to the query string. I.e. http://192.168.0.86:3000/api/config?heatsource=odu%20only&set_changes=1

nebulous commented 1 year ago

https://github.com/nebulous/infinitude/wiki/Infinitude-API-calls

lukazareba commented 1 year ago

@thekev I tried using the browser only. I typed in http://192.168.0.86:3000/api/config/?heatsource=odu only and other than the information from http://192.168.0.86:3000/api/config nothing changed on the thermostat. So please help me how to change it in HA using a script or something else.

Since you’re using the GET method in this case, try adding set_changes=1 to the query string. I.e. http://192.168.0.86:3000/api/config?heatsource=odu%20only&set_changes=1

@thekev it doesn't work unfortunately

nebulous commented 1 year ago

is odu only a valid value? do you have the latest version of Infinitude?

lukazareba commented 1 year ago

It worked, everything works. I made mistakes typing odu_onlyinstead of idu onlyand had an old version of infinitude. Thank you for your help