Skip to content

Commit

Permalink
initial
Browse files Browse the repository at this point in the history
  • Loading branch information
kdudkov committed Jul 6, 2020
0 parents commit e872c94
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea
*.log
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Software for CO2 Monitor

based on https://github.com/dmage/co2mon, more suitable for cron job to send data over MQTT


## See also
* [ZyAura ZG01C Module Manual](http://www.zyaura.com/support/manual/pdf/ZyAura_CO2_Monitor_ZG01C_Module_ApplicationNote_141120.pdf)
* [RevSpace CO2 Meter Hacking](https://revspace.nl/CO2MeterHacking)
* [Photos of the device and the circuit board](http://habrahabr.ru/company/masterkit/blog/248403/)

9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module co2mon

go 1.14

require (
github.com/eclipse/paho.mqtt.golang v1.2.0
github.com/karalabe/hid v1.0.0
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
)
13 changes: 13 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
github.com/eclipse/paho.mqtt.golang v1.2.0 h1:1F8mhG9+aO5/xpdtFkW4SxOJB67ukuDC3t2y2qayIX0=
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
github.com/karalabe/hid v1.0.0 h1:+/CIMNXhSU/zIJgnIvBD2nKHxS/bnRHhhs9xBryLpPo=
github.com/karalabe/hid v1.0.0/go.mod h1:Vr51f8rUOLYrfrWDFlV12GGQgM5AT8sVh+2fY4MPeu8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
136 changes: 136 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package main

import (
"errors"
"flag"
"fmt"
"os"
"time"

MQTT "github.com/eclipse/paho.mqtt.golang"
"github.com/karalabe/hid"
)

var (
temperature float32
co2 uint16
)

func getData(dev *hid.Device) error {
buf := make([]byte, 8)

i, err := dev.Read(buf)
if err != nil {
return err
}

if i != len(buf) {
return errors.New("wrong read bug size")
}

decode(buf)
return nil
}

func decode(buf []byte) {
res := make([]byte, 8)

var c byte
for _, n := range [][]int{{0, 2}, {1, 4}, {3, 7}, {5, 6}} {
c = buf[n[0]]
buf[n[0]] = buf[n[1]]
buf[n[1]] = c
}

var tmp = buf[7] << 5
res[7] = (buf[6] << 5) | (buf[7] >> 3)
res[6] = (buf[5] << 5) | (buf[6] >> 3)
res[5] = (buf[4] << 5) | (buf[5] >> 3)
res[4] = (buf[3] << 5) | (buf[4] >> 3)
res[3] = (buf[2] << 5) | (buf[3] >> 3)
res[2] = (buf[1] << 5) | (buf[2] >> 3)
res[1] = (buf[0] << 5) | (buf[1] >> 3)
res[0] = tmp | (buf[0] >> 3)

var magicWord = []byte("Htemp99e")

for i := 0; i < 8; i++ {
res[i] -= (magicWord[i] << 4) | (magicWord[i] >> 4)
}

if res[3] != res[0]+res[1]+res[2] {
return
}

var w uint16
w = uint16(res[1])*256 + uint16(res[2])

switch res[0] {
case 0x42:
temperature = float32(w)*0.0625 - 273.15
case 0x50:
co2 = w
}
}

func sendMqtt(server, topic, user, password string) error {
opts := MQTT.NewClientOptions()
opts.AddBroker(server)
opts.SetClientID("mqtt-go-sender")
opts.SetUsername(user)
opts.SetPassword(password)

client := MQTT.NewClient(opts)
if token := client.Connect(); token.Wait() && token.Error() != nil {
return token.Error()
}

token := client.Publish(topic+"/temperature", 0, false, fmt.Sprintf("%.2f", temperature))
token.Wait()
token = client.Publish(topic+"/co2", 0, false, fmt.Sprintf("%d", co2))
token.Wait()

client.Disconnect(250)
return nil
}

func main() {
server := flag.String("server", "", "The broker URI. ex: tcp://192.168.0.1:1883")
topic := flag.String("topic", "dadget/room", "Base topic to send to")
user := flag.String("user", "", "The User (optional)")
password := flag.String("password", "", "The password (optional)")

flag.Parse()

devs := hid.Enumerate(0x04d9, 0xa052)
if len(devs) == 0 {
fmt.Println("device not found")
os.Exit(1)
}

dev, err := devs[0].Open()
if err != nil {
fmt.Printf("can't open device - %v\n", err)
os.Exit(1)
}

time.AfterFunc(time.Second*30, func() {
println("timeout...")
os.Exit(2)
})

for temperature == 0 || co2 == 0 {
if err := getData(dev); err != nil {
fmt.Printf("error: %v\n", err)
os.Exit(1)
}
}

fmt.Printf("temp: %.2f\nco2: %d\n", temperature, co2)

if *server != "" {
if err := sendMqtt(*server, *topic, *user, *password); err != nil {
fmt.Printf("error: %v\n", err)
}
}
}

0 comments on commit e872c94

Please sign in to comment.