-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit dff5089
Showing
22 changed files
with
1,648 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
on: | ||
push: | ||
tags: | ||
- '*' | ||
|
||
permissions: | ||
contents: write | ||
|
||
name: Release | ||
|
||
jobs: | ||
release: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v2 | ||
with: | ||
fetch-depth: 0 | ||
|
||
- name: Install Go | ||
uses: actions/setup-go@v3 | ||
with: | ||
go-version: 1.18 | ||
cache: true | ||
|
||
- name: Fetch all tags | ||
run: git fetch --force --tags | ||
|
||
- name: Run GoReleaser | ||
uses: goreleaser/goreleaser-action@v2 | ||
with: | ||
version: latest | ||
args: release --rm-dist | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
on: [push, pull_request] | ||
name: Test | ||
jobs: | ||
test: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: actions/setup-go@v3 | ||
with: | ||
go-version: 1.18 | ||
cache: true | ||
- run: go test ./... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# built executable | ||
aranet4-exporter | ||
|
||
# default directory for homekit db | ||
db/ | ||
|
||
.idea/ | ||
.idea_modules/ | ||
*.iml | ||
*.iws | ||
out/ | ||
dist/ | ||
nocommit* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
project_name: aranet4-exporter | ||
## Uncomment if/when `go mod tidy` doesn't break. | ||
#before: | ||
# hooks: | ||
# - go mod tidy | ||
# - go generate ./... | ||
builds: | ||
- env: | ||
- CGO_ENABLED=0 | ||
goos: | ||
- linux | ||
goarch: | ||
- amd64 | ||
- arm64 | ||
- arm | ||
archives: | ||
- replacements: | ||
darwin: Darwin | ||
linux: Linux | ||
windows: Windows | ||
386: i386 | ||
amd64: x86_64 | ||
checksum: | ||
name_template: 'checksums.txt' | ||
snapshot: | ||
name_template: "{{ incpatch .Version }}-next" | ||
changelog: | ||
sort: asc | ||
filters: | ||
exclude: | ||
- '^docs:' | ||
- '^test:' | ||
nfpms: | ||
- vendor: ryry | ||
description: Aranet4 compatible Prometheus exporter and HomeKit bridge. | ||
maintainer: ryry | ||
formats: | ||
- deb | ||
contents: | ||
- dst: ./usr/share/lintian/overrides/aranet4-exporter | ||
src: packaging/lintian-overrides | ||
packager: deb | ||
file_info: | ||
owner: root | ||
group: root | ||
mode: 0644 | ||
- dst: /etc/default/aranet4-exporter | ||
src: packaging/default.aranet4-exporter | ||
type: config | ||
file_info: | ||
owner: root | ||
group: root | ||
mode: 0644 | ||
- dst: /usr/lib/systemd/system/aranet4-exporter.service | ||
src: packaging/aranet4-exporter.service | ||
file_info: | ||
owner: root | ||
group: root | ||
mode: 0644 | ||
scripts: | ||
postinstall: packaging/postinst.sh | ||
postremove: packaging/postrm.sh | ||
preremove: packaging/prerm.sh | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# aranet4-exporter-go | ||
|
||
aranet4-exporter-go is a Prometheus exporter for the [Aranet4](https://aranet.com/products/aranet4/) environmental | ||
sensing devices. Use this to add the CO2, temperature, and humidity readings from your Aranet4 devices to your | ||
Prometheus dashboards. | ||
|
||
## Requirements | ||
|
||
aranet4-exporter-go should work on most modern Linux system with Bluetooth support. | ||
|
||
It has been tested on these platforms: | ||
|
||
* x86 Ubuntu 22.04 | ||
* Raspberry Pi / Raspbian 3b 32-bit | ||
|
||
## Installing | ||
|
||
Debian-based distributions can download .deb packages from | ||
the [releases](https://github.com/ryansouza/aranet4-exporter-go/releases). | ||
|
||
## Setup | ||
|
||
These instructions assume you are on a system using systemd and bluetoothctl. | ||
|
||
1. Use bluetoothctl to pair with your Aranet4 device as follows: | ||
|
||
```shell | ||
$ bluetoothctl | ||
> power on | ||
> scan on | ||
> scan off | ||
# find the MAC address of the Aranet4 device in the output. | ||
> pair XX:XX:.. | ||
# ... enter passcode shown on Aranet4 ... | ||
> trust XX:XX:.. | ||
``` | ||
|
||
2. If `bluetoothctl` is not installed, you may need to install it: | ||
|
||
```shell | ||
# Raspbian | ||
$ sudo apt-get install --no-install-recommends bluetooth pi-bluetooth bluez | ||
# Other distros | ||
$ sudo apt-get install --no-install-recommends bluetooth bluez | ||
``` | ||
|
||
3. Add the MAC address and optional nickname of your devices to `/etc/default/aranet4-exporter`. | ||
|
||
4. Run `systemctl restart aranet4-exporter`. | ||
|
||
5. Run `journalctl status aranet4-exporter` to get the port that the daemon was started on, and add the URL to your | ||
Prometheus collector. Example: TODO(ryansouze) | ||
|
||
## Releasing | ||
|
||
### Building release with goreleaser | ||
|
||
To add a new versioned release: | ||
|
||
```shell | ||
$ git tag -a v0.1.0 -m "v0.1.0" | ||
$ git push origin v0.1.0 | ||
``` | ||
|
||
### Building snapshot release with goreleaser | ||
|
||
Snapshot build: | ||
|
||
```shell | ||
$ podman run --rm --privileged \ | ||
-v $PWD:/go/src/github.com/user/repo \ | ||
-w /go/src/github.com/user/repo \ | ||
-e GITHUB_TOKEN \ | ||
docker.io/goreleaser/goreleaser release --snapshot --rm-dist | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package aranet | ||
|
||
import ( | ||
"github.com/brutella/hap/accessory" | ||
"github.com/brutella/hap/characteristic" | ||
"github.com/brutella/hap/service" | ||
"log" | ||
"sbinet.org/x/aranet4" | ||
) | ||
|
||
var qualityMap = map[int]int{1: 1, 2: 3, 3: 5} | ||
|
||
type Accessory struct { | ||
*accessory.A | ||
TempSensor *service.TemperatureSensor | ||
AranetCO2Sensor *AranetCO2Sensor | ||
HumiditySensor *service.HumiditySensor | ||
BatteryService *service.BatteryService | ||
} | ||
|
||
// NewAranetAccessory returns a Thermometer which implements model.Thermometer. | ||
func NewAranetAccessory(info accessory.Info) *Accessory { | ||
a := Accessory{} | ||
a.A = accessory.New(info, accessory.TypeSensor) | ||
|
||
a.TempSensor = service.NewTemperatureSensor() | ||
a.AddS(a.TempSensor.S) | ||
|
||
a.AranetCO2Sensor = NewAranetCO2Sensor() | ||
a.AddS(a.AranetCO2Sensor.S) | ||
|
||
a.HumiditySensor = service.NewHumiditySensor() | ||
a.AddS(a.HumiditySensor.S) | ||
|
||
a.BatteryService = service.NewBatteryService() | ||
a.AddS(a.BatteryService.S) | ||
|
||
return &a | ||
} | ||
|
||
func (acc *Accessory) Update(data aranet4.Data) { | ||
acc.TempSensor.CurrentTemperature.SetValue(data.T) | ||
acc.AranetCO2Sensor.CarbonDioxideLevel.SetValue(float64(data.CO2)) | ||
if err := acc.AranetCO2Sensor.AirQuality.SetValue(qualityMap[int(data.Quality)]); err != nil { | ||
log.Printf("Failed to accept air quality: %v", err) | ||
} | ||
acc.HumiditySensor.CurrentRelativeHumidity.SetValue(data.H) | ||
if err := acc.BatteryService.BatteryLevel.SetValue(data.Battery); err != nil { | ||
log.Printf("Failed to accept battery level: %v", err) | ||
} | ||
} | ||
|
||
type AranetCO2Sensor struct { | ||
*service.S | ||
|
||
AirQuality *characteristic.AirQuality | ||
CarbonDioxideLevel *characteristic.CarbonDioxideLevel | ||
} | ||
|
||
func NewAranetCO2Sensor() *AranetCO2Sensor { | ||
s := AranetCO2Sensor{} | ||
s.S = service.New(service.TypeAirQualitySensor) | ||
|
||
s.AirQuality = characteristic.NewAirQuality() | ||
s.AddC(s.AirQuality.C) | ||
|
||
s.CarbonDioxideLevel = characteristic.NewCarbonDioxideLevel() | ||
s.AddC(s.CarbonDioxideLevel.C) | ||
|
||
return &s | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package aranet | ||
|
||
import ( | ||
"context" | ||
"log" | ||
"time" | ||
|
||
"github.com/brutella/hap/accessory" | ||
"sbinet.org/x/aranet4" | ||
) | ||
|
||
type AranetData interface { | ||
Read() aranet4.Data | ||
Room() string | ||
} | ||
|
||
type Aranet struct { | ||
accessory *Accessory | ||
id string | ||
room string | ||
context context.Context | ||
ticker time.Ticker | ||
retriever Retriever | ||
} | ||
|
||
func New(context context.Context, id string, room string) *Aranet { | ||
retriever := Retriever{ID: id} | ||
acc := NewAranetAccessory(accessory.Info{Name: "Aranet4"}) | ||
return &Aranet{ | ||
accessory: acc, | ||
context: context, | ||
id: id, | ||
retriever: retriever, | ||
room: room, | ||
} | ||
} | ||
|
||
func (a *Aranet) RunUpdateLoop(verbose bool) { | ||
ticker := time.NewTicker(10 * time.Second) | ||
defer ticker.Stop() | ||
log.Printf("Monitoring aranet %s as room=%s", a.id, a.room) | ||
|
||
data := a.retriever.Read() | ||
|
||
for { | ||
select { | ||
case <-ticker.C: | ||
if verbose { | ||
log.Println("tick") | ||
} | ||
|
||
if time.Since(data.Time) < data.Interval { | ||
continue | ||
} | ||
|
||
if verbose { | ||
log.Println("updating") | ||
} | ||
|
||
if err := a.retriever.Update(); err != nil { | ||
log.Printf("failed update (%s): %v", a.id, err) | ||
continue | ||
} | ||
data = a.retriever.Read() | ||
if verbose { | ||
log.Printf("got: %#v\n", data) | ||
} | ||
|
||
a.accessory.Update(data) | ||
case <-a.context.Done(): | ||
log.Println("Stopped updating loop") | ||
return | ||
} | ||
} | ||
} | ||
|
||
func (a *Aranet) Read() aranet4.Data { | ||
return a.retriever.Read() | ||
} | ||
|
||
func (a *Aranet) Room() string { | ||
return a.room | ||
} | ||
|
||
func (a *Aranet) Accessory() *Accessory { | ||
return a.accessory | ||
} |
Oops, something went wrong.