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

#1 Add DHT22 room temperature sensor #2

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ Currently supporting:
| `12` GPIO18 | `s` |
| `01` 3.3V | `middle` |

| Raspberry Pi pin | DHT22 temperature sensor pin |
| - | - |
| `17` 3.3V | `1` VCC |
| `07` GPIO4 | `2` Data |
| `-` Not connected | `3` Not connected |
| `20` Ground | `4` Ground |

## Software

* Install `LIRC`: `sudo apt install lirc`
Expand All @@ -38,6 +45,18 @@ Currently supporting:
* In the Home app on your iOS device, add a new accessory with the code: `00102003`
* To control a Dyson Hot + Cool AM09 fan heater, run with the `-dyson` flag: `go run homekit-daikin-infrared.go -dyson`

### With a DHT22 temperature sensor

**Notes**:

* Building on macOS no longer works due to the [go-dht](https://github.com/d2r2/go-dht) library
* After running on a Raspberry pi with `sudo` to access the DHT22 via GPIO the `./db` directory will be owned by the `root` user

**Build and run**

* Build on the Raspberry Pi: `go build homekit-daikin-infrared.go`
* Run the executable: `sudo /usr/local/go/bin/go run homekit-daikin-infrared.go -temperaturePin 4`

### LIRC

To detect IR codes, run: `mode2`
Expand Down
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ require github.com/brutella/hap v0.0.15
require (
github.com/brutella/dnssd v1.2.1 // indirect
github.com/chbmuc/lirc v0.0.0-20150702183631-f5796a80dd2b // indirect
github.com/d2r2/go-dht v0.0.0-20200119175940-4ba96621a218 // indirect
github.com/d2r2/go-logger v0.0.0-20210606094344-60e9d1233e22 // indirect
github.com/d2r2/go-shell v0.0.0-20211022052110-f591c27e3e2e // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-chi/chi v1.5.4 // indirect
github.com/miekg/dns v1.1.1 // indirect
github.com/tadglines/go-pkgs v0.0.0-20210623144937-b983b20f54f9 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@ github.com/brutella/hap v0.0.15 h1:XrGBWkUtlQp2ZnjpaQVAUAAPnnI7BFeqOODdCXcEU1g=
github.com/brutella/hap v0.0.15/go.mod h1:bpOEXdJ80ZI2lphDz+jdO0RoyQOn3tWeBDhts98sYF4=
github.com/chbmuc/lirc v0.0.0-20150702183631-f5796a80dd2b h1:i8K874dgs0m4A98xPutUOAsxYCQxXvEeaW986Wv5vQY=
github.com/chbmuc/lirc v0.0.0-20150702183631-f5796a80dd2b/go.mod h1:9zpQpkg+zE2TAzAEgMAwdr0bTwjdj4kcHo9yNCVK770=
github.com/d2r2/go-dht v0.0.0-20200119175940-4ba96621a218 h1:z3u7ZAkBvqHD2zaECn0qd1BwMCTiAYcQjFdU8vflVHo=
github.com/d2r2/go-dht v0.0.0-20200119175940-4ba96621a218/go.mod h1:AzSqP4S4/6pINOKg3VC79WC7YY3zskQcrXMFzphCry0=
github.com/d2r2/go-logger v0.0.0-20210606094344-60e9d1233e22 h1:nO+SY4KOMsF/LsZ5EtbSKhiT3M6sv/igo2PEru/xEHI=
github.com/d2r2/go-logger v0.0.0-20210606094344-60e9d1233e22/go.mod h1:eSx+YfcVy5vCjRZBNIhpIpfCGFMQ6XSOSQkDk7+VCpg=
github.com/d2r2/go-shell v0.0.0-20211022052110-f591c27e3e2e h1:6rbw4kecquuE5mELvn9DJqrFfTLkeITQSkv8chVAX2Q=
github.com/d2r2/go-shell v0.0.0-20211022052110-f591c27e3e2e/go.mod h1:yqtlOXB0bWzWgM4wZ9BdZ75OmXSiFYSKrZ3TZlPaePQ=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs=
github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIuEg=
github.com/miekg/dns v1.1.1 h1:DVkblRdiScEnEr0LR9nTnEQqHYycjkXW9bOjd+2EL2o=
Expand Down
97 changes: 59 additions & 38 deletions homekit-daikin-infrared.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/brutella/hap/accessory"
"github.com/brutella/hap/characteristic"
"github.com/chbmuc/lirc"
"github.com/d2r2/go-dht"

"context"
"flag"
Expand All @@ -15,8 +16,10 @@ import (
"os/signal"
"strconv"
"syscall"
"time"
)

var acc *accessory.Heater
var currentFanSpeed float64
var currentHeaterCoolerState int
var currentHeatingThresholdTemperature float64
Expand All @@ -28,10 +31,27 @@ var ir *lirc.Router
var lircName string
var fanSpeed *characteristic.RotationSpeed
var swingMode *characteristic.SwingMode
var temperaturePin int

func readTemperature() {
if temperaturePin != 0 {
for {
temperature, humidity, retried, err := dht.ReadDHTxxWithRetry(dht.DHT22, temperaturePin, false, 10)
if err != nil {
log.Println(fmt.Sprintf("Failed to get temperature with error: %s", err))
} else {
log.Println(fmt.Sprintf("Temperature = %f°C, Humidity = %f% (retried %d times)", temperature, humidity, retried))
acc.Heater.CurrentTemperature.SetValue(float64(temperature))
}
time.Sleep(5 * time.Second)
}
}
}

func init() {
flag.BoolVar(&developmentMode, "dev", false, "development mode, so ignore LIRC setup")
flag.BoolVar(&dyson, "dyson", false, "Dyson AM09 mode")
flag.IntVar(&temperaturePin, "temperaturePin", 0, "tempearture sensor GPIO pin, an int")
flag.Parse()

// Initialize with path to lirc socket
Expand All @@ -41,6 +61,25 @@ func init() {
}
ir = lircIr

// Create the heater accessory.
info := accessory.Info{
Name: "Daikin air conditioner",
SerialNumber: "FTXS50KAVMA",
Manufacturer: "Daikin",
Model: "FTXS50KAVMA",
Firmware: "1.0.0",
}
lircName = "daikin"

if dyson {
info.Name = "Dyson Hot+Cool"
info.SerialNumber = "AM09"
info.Manufacturer = "Dyson"
info.Model = "AM09"
lircName = "dyson-am09"
}
acc = accessory.NewHeater(info)

// Store the data in the "./db" directory.
fs = hap.NewFsStore("./db")

Expand Down Expand Up @@ -83,23 +122,6 @@ func sendLircCommand(command string) {
}

func main() {
info := accessory.Info{
Name: "Daikin air conditioner",
SerialNumber: "FTXS50KAVMA",
Manufacturer: "Daikin",
Model: "FTXS50KAVMA",
Firmware: "1.0.0",
}
lircName = "daikin"

if dyson {
info.Name = "Dyson Hot+Cool"
info.SerialNumber = "AM09"
info.Manufacturer = "Dyson"
info.Model = "AM09"
lircName = "dyson-am09"
}

log.Println(fmt.Sprintf(
"Starting up %s, state: %d, temperature: %f, fan: %f, swing mode: %d",
lircName,
Expand All @@ -109,34 +131,30 @@ func main() {
currentSwingMode,
))

// Create the heater accessory.
a := accessory.NewHeater(info)

// TODO: read room temperature from a sensor
// a.Heater.CurrentTemperature.SetValue(19)

a.Heater.TargetHeaterCoolerState.SetValue(currentHeaterCoolerState)
// Set target state
acc.Heater.TargetHeaterCoolerState.SetValue(currentHeaterCoolerState)

// Set target temperature
a.Heater.HeatingThresholdTemperature.SetValue(currentHeatingThresholdTemperature)
a.Heater.HeatingThresholdTemperature.SetStepValue(1.0)
a.Heater.HeatingThresholdTemperature.SetMinValue(18)
a.Heater.HeatingThresholdTemperature.SetMaxValue(26)
acc.Heater.HeatingThresholdTemperature.SetValue(currentHeatingThresholdTemperature)
acc.Heater.HeatingThresholdTemperature.SetStepValue(1.0)
acc.Heater.HeatingThresholdTemperature.SetMinValue(18)
acc.Heater.HeatingThresholdTemperature.SetMaxValue(26)
if dyson {
a.Heater.HeatingThresholdTemperature.SetMinValue(1)
a.Heater.HeatingThresholdTemperature.SetMaxValue(37)
acc.Heater.HeatingThresholdTemperature.SetMinValue(1)
acc.Heater.HeatingThresholdTemperature.SetMaxValue(37)
}

a.Heater.Active.OnValueRemoteUpdate(func(on int) {
acc.Heater.Active.OnValueRemoteUpdate(func(on int) {
if on == 1 {
log.Println("Sending power on command")
powerOnCommand := fmt.Sprintf("%s POWER_ON", lircName)
if currentHeaterCoolerState == 1 && dyson == false {
powerOnCommand = fmt.Sprintf("%s POWER_ON_HEAT", lircName)
currentHeatingThresholdTemperature = 25.0
acc.Heater.HeatingThresholdTemperature.SetValue(currentHeatingThresholdTemperature)
}
a.Heater.HeatingThresholdTemperature.SetValue(currentHeatingThresholdTemperature)
a.Heater.TargetHeaterCoolerState.SetValue(currentHeaterCoolerState)
acc.Heater.HeatingThresholdTemperature.SetValue(currentHeatingThresholdTemperature)
acc.Heater.TargetHeaterCoolerState.SetValue(currentHeaterCoolerState)
fanSpeed.SetValue(currentFanSpeed)
swingMode.SetValue(currentSwingMode)
sendLircCommand(powerOnCommand)
Expand All @@ -146,7 +164,7 @@ func main() {
}
})

a.Heater.HeatingThresholdTemperature.OnValueRemoteUpdate(func(value float64) {
acc.Heater.HeatingThresholdTemperature.OnValueRemoteUpdate(func(value float64) {
state := "AUTO"
if currentHeaterCoolerState == 1 {
state = "HEAT"
Expand All @@ -167,7 +185,7 @@ func main() {
fs.Set("currentHeatingThresholdTemperature", []byte(fmt.Sprintf("%d", int(currentHeatingThresholdTemperature))))
})

a.Heater.TargetHeaterCoolerState.OnValueRemoteUpdate(func(value int) {
acc.Heater.TargetHeaterCoolerState.OnValueRemoteUpdate(func(value int) {
state := "AUTO"
if value == 1 {
state = "HEAT"
Expand Down Expand Up @@ -212,7 +230,7 @@ func main() {
currentFanSpeed = percentageToSpeed
fs.Set("currentFanSpeed", []byte(fmt.Sprintf("%d", int(currentFanSpeed))))
})
a.Heater.AddC(fanSpeed.C)
acc.Heater.AddC(fanSpeed.C)

// Add swing mode
swingMode = characteristic.NewSwingMode()
Expand All @@ -229,10 +247,10 @@ func main() {
currentSwingMode = value
fs.Set("currentSwingMode", []byte(fmt.Sprintf("%d", currentSwingMode)))
})
a.Heater.AddC(swingMode.C)
acc.Heater.AddC(swingMode.C)

// Create the hap server.
server, err := hap.NewServer(fs, a.A)
server, err := hap.NewServer(fs, acc.A)
if err != nil {
// stop if an error happens
log.Panic(err)
Expand All @@ -254,6 +272,9 @@ func main() {
cancel()
}()

// Read room temperature from a DHT22 temperature sensor
go readTemperature()

// Run the server.
server.ListenAndServe(ctx)
}