arachnetech / homebridge-mqttthing

A plugin for Homebridge allowing the integration of many different accessory types using MQTT.
Apache License 2.0
462 stars 104 forks source link

Request: Thermostat #107

Closed Denny5667 closed 4 years ago

Denny5667 commented 5 years ago

Would it be possible to implement "Thermostat" as an accessory?

arachnetech commented 5 years ago

See also #66.

arachnetech commented 5 years ago

Added in version 1.0.37.

al-ivanov commented 5 years ago

Is it possible to change min temperature and max temperature limits?

alexair777 commented 5 years ago

that's fantastic, thanks so much!

arachnetech commented 5 years ago

@al-ivanov I’ll have a look - it may be possible to change the HomeKit defaults.

al-ivanov commented 5 years ago

@arachnetech Ok, thanks a lot

Denny5667 commented 5 years ago

@arachnetech you are the man! Thanks a lot!

arachnetech commented 5 years ago

:-) I'm delighted that other people can use something which I initially created just for my own home automation experiments!

arachnetech commented 5 years ago

Min/max target temperature in 1.0.38.

Denny5667 commented 5 years ago

You do a very good job! Thanks to your plugin i was motivated to automate all the stuff in my flat (lights, fans, window shades, alarm system, temperature sensors, laundry stuff) and everything works without any issues since months. So, now is the turn to automate the heating :) Thanks once again!

tobekas commented 5 years ago

It will also make sense to specify the valid values for HeatingCoolingState, since you may want to restrict some modes. You can have:

The invalid values are then also hidden in the Home app.

tobekas commented 5 years ago

And to complete this topic: There is also a new HeaterCoolor Service available, that also supports some fan characteristics. This is besser suited for AirConditioners. Some Characteristics seem to be duplicates, but are not (Heating vs. Heater, ...).

arachnetech commented 5 years ago

@tobekas How can the valid values for HeatingCoolingState be limited - I hadn't realised it was possible to change the options in the HAPTypes enumerations?

Maybe I can change validValues just like minValue and maxValue can be changed. I'll try it.

tobekas commented 5 years ago

yes, you can change validValues just like minValue, maxValueor minStep (for Float types): carac.setProps(myPropObj) or just carac.props.validValues = [0,1];

Would it be a good idea to add this opportunity for all types? So, a generic optional property override? This would make it easier to play with...

arachnetech commented 5 years ago

Thanks, Tobekas - yes, I tried that and it worked. Very handy. Generic would be good, but tricky where one device supports multiple properties. It could perhaps be done as a map.

tobekas commented 5 years ago

You are right. Generic is difficult because it‘s related to characteristics and not for all of them it actually makes sense. Think it makes more sense to pick out a few properties, where it is helpful to change the properties.

For example it makes sense for: SetDuration (maxValue), SecuritySystem (validValues), TargetHeatingCoolingState (validValues), maybe LockMechanism (validValues)?

Denny5667 commented 5 years ago

@arachnetech is there is a way to hide some modes like auto and cooling from the home app? I would like to control only the heater. And what is the proper way to adjust temperature range? If I define minimum and maximum values like "minTemperature": "15“, maxTemperature": „30“ the Apple home service crashes and after restarting it shows, that all of my devices are not reachable anymore

arachnetech commented 5 years ago

Yes, ability to adjust modes is coming.

I’ve seen ‘not responding’ when changing the temperature ranges too, but it seems to sort itself out in the end. How are you restarting the home service, out of interest? Can it be restarted independently of the Home App?

tobekas commented 5 years ago

min/max values should not be strings...?

arachnetech commented 5 years ago

Good spot, @tobekas - my fault for reading/responding from phone.

Yes - @Denny5667 please try "minTemperature": 15, "maxTemperature": 30

ghostseven commented 5 years ago

I am having some real issues getting this to work correctly, I can get the current temperature but anything to do with state and target temperatures is just not playing ball. I wonder if anyone has a working configuration that they are using and can share. I know my message are getting through the broker but just not working for me at this end.

I am mainly just interested in running this for cooling (it is for temperature controlled socked tied to a fan) but any working examples would help we work out what I am doing wrong!

Thanks.

rebelnme commented 5 years ago

I really appreciate all the work you have done on this project. I am using multiple items from the project and they are all have been working great. I just added the thermostat and am having trouble with it. I am writing to provide feedback and am happy you've added it to to the package as well. The current temperature it shows is 162 degrees. The thermostat actually shows 72 F. It appears to convert the current temperature into Fahrenheit from Fahrenheit assuming the original is Celsius. I have the Fahrenheit unit selected in the home app. Secondly the min/max settings are 65 min and 77 max, in the home app it shows 77 min and 97 max. I will provide any data you need to help resolve this.
thank you.

arachnetech commented 5 years ago

@ghostseven My test configuration is:

    {
      "accessory": "mqttthing",
      "type": "thermostat",
      "name": "Thermostat",
      "url": "http://192.168.10.35:1883",
      "logMqtt": "true",
      "topics": {
        "getCurrentHeatingCoolingState": "test/thermostat/getCurrentState",
        "setCurrentHeatingCoolingState": "test/thermostat/setCurrentState",
        "getTargetHeatingCoolingState": "test/thermostat/getTargetState",
        "setTargetHeatingCoolingState": "test/thermostat/setTargetState",
        "getCurrentTemperature": "test/thermostat/getCurrentTemperature",
        "setTargetTemperature": "test/thermostat/setTargetTemperature",
        "getTargetTemperature": "test/thermostat/getTargetTemperature",
        "setTemperatureDisplayUnits": "test/thermostat/setTemperatureDisplayUnits",
        "getTemperatureDisplayUnits": "test/thermostat/getTemperatureDisplayUnits"
      },
      "minTemperature": 5,
      "maxTemperature": 27.5
}
arachnetech commented 5 years ago

@rebelnme I believe unit default to Celsius. I appear to have misspelt Fahrenheit as FARENHEIT which may not be helping! I'll do some investigation and come back to you.

arachnetech commented 5 years ago

@rebelnme "It appears to convert the current temperature into Fahrenheit from Fahrenheit assuming the original is Celsius." - I can't reproduce this. In my tests, Homekit just seems to accept the numbers that it's passed as numbers and display them. I'm certainly not doing any conversions in mqttthing.

Are you able to share more details of your configuration and the MQTT messages that are being sent?

I have corrected the spelling of Fahrenheit in the latest version.

tobekas commented 5 years ago

I think within HomeKit, temperature characteristic value is always Celsius. Depending on the iOS Language settings, temperature can be shown in Fahrenheit (iOS converts C to F internally). The optional DisplayUnits characteristic, which can be set within Thermostat settings, is only meant to be able to switch the unit on the device’s physical display, not within Home App and not for MQTT payload.

rebelnme commented 5 years ago

I have the homebridge UI plugin with the accessories enabled and it is showing the 162 degrees F as well. so it isn't a Home App issue, it must be a homebridge issue because it is showing the same error in homebridge.

rebelnme commented 5 years ago

This is the homebridge configuration: { "accessory": "mqttthing", "type": "thermostat", "name": "Thermostat", "url": "mqtt://127.0.0.1:1883", "logMqtt": "true", "topics": { "getCurrentHeatingCoolingState": "home/downstairs_thermostat/thermostatMode", "setTargetHeatingCoolingState": "home/downstairs_thermostat/setThermostatMode", "getTargetHeatingCoolingState": "home/downstairs_thermostat/thermostatMode", "getCurrentTemperature": "home/downstairs_thermostat/temperature", "setTargetTemperature": "home/downstairs_thermostat/thermostatSetpoint", "getTargetTemperature": "home/downstairs_thermostat/thermostatSetpoint", "setTemperatureDisplayUnits": "home/downstairs_thermostat/displayUnits", "getTemperatureDisplayUnits": "home/downstairs_thermostat/displayUnits", "setCoolingThresholdTemperature": "home/downstairs_thermostat/setCoolingSetpoint", "getCoolingThresholdTemperature": "home/downstairs_thermostat/coolingSetpoint", "setHeatingThresholdTemperature": "home/downstairs_thermostat/setHeatingSetpoint", "getHeatingThresholdTemperature": "home/downstairs_thermostat/heatingSetpoint" }, "heatingCoolingStateValues": [ "off", "heat", "cool", "auto" ], "minTemperature": 65, "maxTemperature": 77 },

This is my data from MQTT: downstairs_thermostat displayUnits = FAHRENHEIT heatingSetpoint = 70 thermostatSetpoint = 70 temperature = 72 coolingSetpoint = 73 setThermostatMode = Auto setHeatingSetpoint = 70.0 setCoolingSetpoint = 73.0

tobekas commented 5 years ago

Is I said, you must always use Celsius for your Mqtt data and your min/max limits! This is specified by Apple:

Target Temperature - This characteristic describes the target temperature in Celsius that the device is actively attempting to reach. For example, a thermostat cooling a room to "75" degrees Fahrenheit would set the target temperature value to "23.9".

Current Temperature This characteristic describes the current temperature of the environment in Celsius irrespective of display units chosen in Temperature Display Units (page 163).

Maybe there is a bug within Homebridge UI. What is crucial is what you see in the Home App. All client app have to do the conversion by itself.

rebelnme commented 5 years ago

If you do the temperature conversion, something is converting the original MQTT temperature to Fahrenheit (assuming it is Celsius). Maybe both the Home app and the homebridge UI do the conversion, or maybe it is coming from the MQTT plugin. If the original MQTT data has to be Celsius for the plugin to work, then every Fahrenheit thermostat will not work and there needs to be a disclaimer. If the creators add a setting that says original data is Fahrenheit and then do the conversions accordingly; then we have a winner. That is all I was asking if it was possible.

tobekas commented 5 years ago

ok, in summary: If you have a Fahrenheit Thermostat, and mqtt-values are send/received in °F, values must be scaled, because Apple Homekit protocol requires Celsius.

For this scaling you could use the apply-feature (see readme) even now! And min/max options in config.json must be the corresponding celsius values.

Much more elegant would be an option for this automatic conversion (°F to °C) by this plugin (Homebridge-Mqttthing). @arachnetech: Is it possible to add an option, which generates this apply function internally for alle temp characteristics?

arachnetech commented 5 years ago

Yes, I was thinking the same! A small project for the weekend, perhaps. 🙂

rebelnme commented 5 years ago

I wanted to say thanks for the tip on using the message equation. I finally got it working correctly. I updated my configuration as follows: { "accessory": "mqttthing", "type": "thermostat", "name": "Upstairs Thermostat", "url": "mqtt://127.0.0.1:1883", "username": "xxxxx", "password": "xxxxx", "logMqtt": "true", "topics": { "getCurrentHeatingCoolingState": "home/uptairs_thermostat/thermostatMode", "setTargetHeatingCoolingState": "home/upstairs_thermostat/setThermostatMode", "getTargetHeatingCoolingState": "home/upstairs_thermostat/thermostatMode", "getCurrentTemperature": { "topic": "home/upstairs_thermostat/temperature", "apply": "return Math.round( (message - 32) 0.5556 );" }, "setTargetTemperature": { "topic": "home/upstairs_thermostat/thermostatSetpoint", "apply": "return Math.round( message 1.8 + 32 );" }, "getTargetTemperature": { "topic": "home/upstairs_thermostat/thermostatSetpoint", "apply": "return Math.round( (message - 32) 0.5556 );" }, "setTemperatureDisplayUnits": "home/upstairs_thermostat/displayUnits", "getTemperatureDisplayUnits": "home/upstairs_thermostat/displayUnits", "setCoolingThresholdTemperature": { "topic": "home/upstairs_thermostat/setCoolingSetpoint", "apply": "return Math.round( message 1.8 + 32 );" }, "getCoolingThresholdTemperature": { "topic": "home/upstairs_thermostat/coolingSetpoint", "apply": "return Math.round( (message - 32) 0.5556 );" }, "setHeatingThresholdTemperature": { "topic": "home/upstairs_thermostat/setHeatingSetpoint", "apply": "return Math.round( message 1.8 + 32 );" }, "getHeatingThresholdTemperature": { "topic": "home/upstairs_thermostat/heatingSetpoint", "apply": "return Math.round( (message - 32) * 0.5556 );" } }, "heatingCoolingStateValues": [ "off", "heat", "cool", "auto" ] },

arachnetech commented 4 years ago

Glad the ever-useful apply function gave you a solution.