Skip to content

Commit

Permalink
Merge pull request #1 from doniacld/dev
Browse files Browse the repository at this point in the history
Tinyhen project
  • Loading branch information
doniacld committed Jul 22, 2022
2 parents dc639a5 + 932eb6f commit d123e78
Show file tree
Hide file tree
Showing 25 changed files with 2,191 additions and 10 deletions.
Binary file added .DS_Store
Binary file not shown.
16 changes: 16 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: CI
on:
workflow_dispatch:
pull_request:
types: [opened, edited, synchronize, reopened]
push:

jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: build
run: make build

35 changes: 35 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Release

on:
push:
tags:
- '*'

jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
-
name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
# Doc: https://github.com/marketplace/actions/docker-login
- uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v3
with:
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
13 changes: 4 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
bin/
.idea/

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/
# goreleaser directory when generating a dry-run release locally
dist/
56 changes: 56 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# This is an example goreleaser.yaml file with some sane defaults.
# Make sure to check the documentation at http://goreleaser.com
---
before:
hooks:
- "go mod download"
- "go generate ./..."
builds:
-
env:
- CGO_ENABLED=0
- BUILDER=GoReleaser
goos:
- linux
- darwin
main: ./cmd/

release:
github:
owner: doniacld
name: tiny-hen
footer: |
## Docker Images
- docker pull `ghcr.io/doniacld/tiny-hen:{{ .Version }}`
- docker pull `ghcr.io/doniacld/tiny-hen:latest`
dockers:
- image_templates: ["ghcr.io/doniacld/tiny-hen:{{ .Version }}"]
dockerfile: Dockerfile
build_flag_templates:
- --label=org.opencontainers.image.title={{ .ProjectName }}
- --label=org.opencontainers.image.description={{ .ProjectName }}
- --label=org.opencontainers.image.url=https://github.com/doniacld/tiny-hen
- --label=org.opencontainers.image.source=https://github.com/doniacld/tiny-hen
- --label=org.opencontainers.image.version={{ .Version }}
- --label=org.opencontainers.image.revision={{ .FullCommit }}
- --label=org.opencontainers.image.licenses=MIT
- image_templates: ["ghcr.io/doniacld/tiny-hen:latest"]
dockerfile: Dockerfile
build_flag_templates:
- --label=org.opencontainers.image.title={{ .ProjectName }}
- --label=org.opencontainers.image.description={{ .ProjectName }}
- --label=org.opencontainers.image.url=https://github.com/doniacld/tiny-hen
- --label=org.opencontainers.image.source=https://github.com/doniacld/tiny-hen
- --label=org.opencontainers.image.version=latest
- --label=org.opencontainers.image.revision={{ .FullCommit }}
- --label=org.opencontainers.image.licenses=MIT

changelog:
sort: desc

checksum:
name_template: checksums.txt
snapshot:
name_template: "{{ .Tag }}-next"
project_name: tiny-hen
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM scratch
COPY tiny-hen /
ENTRYPOINT ["/tiny-hen"]
69 changes: 69 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Go parameters
GOCMD=go
GOBUILD=$(GOCMD) build
GORUN=$(GOCMD) run
GOCLEAN=$(GOCMD) clean
GOTEST=$(GOCMD) test
GOMOD=$(GOCMD) mod

# Source parameters
SOURCE_ENTRYPOINT=./cmd/main.go

# Binary parameters
BINARY_NAME=tinyhen-server
BINARY_DESTINATION=./bin
BINARY_PATH=$(BINARY_DESTINATION)/$(BINARY_NAME)

# Docker parameters
DOCKERCMD=docker
DOCKERBBUILD=$(DOCKERCMD) build
DOCKERRUN=$(DOCKERCMD) run
DOCKERSTOP=$(DOCKERCMD) stop
DOCKERRM=$(DOCKERCMD) rm

# Development
tidy:
$(GOMOD) tidy
build:
$(GOBUILD) -o $(BINARY_PATH) -v $(SOURCE_ENTRYPOINT)
run:
$(GORUN) $(SOURCE_ENTRYPOINT)
unit_test:
$(GOTEST) -v ./... -coverprofile=coverage.txt -covermode=atomic
clean:
$(GOCLEAN) $(SOURCE_ENTRYPOINT)
rm -f $(BINARY_PATH)

# Docker for local operations
build-linux:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GOBUILD) -o $(BINARY_PATH)-amd64 -v $(SOURCE_ENTRYPOINT)
docker_build: build-linux
$(DOCKERBBUILD) -t tinyhen-server .
docker_run: build-linux docker_build
$(DOCKERRUN) -d -p 10010:10010 tinyhen-server
docker_stop: docker_run
$(DOCKERSTOP) tinyhen-server
docker_rm: docker_run
$(DOCKERRM) tinyhen-server
docker_load:
kind load docker-image tinyhen-server:latest --name tinyhen

# Deployment
.PHONY: deploy
deploy:
./deploy/deploy.sh

grafana:
# Create a port-forward to the grafana server (http://localhost:3000)
kubectl port-forward service/kube-prometheus-stack-grafana 3000:80 -n monitoring

prometheus:
# Create a port-forward to the prometheus server (http://localhost:9090)
kubectl port-forward service/kube-prometheus-stack-prometheus 9090:9090 -n monitoring

destroy:
kind delete cluster --name=tinyhen

# Curls
curl_measure:
curl -v -X POST -H "Content-Type: application/json" http://localhost/measure -d '{"temperature": 31.2, "humidity": 41.6}'
47 changes: 46 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,47 @@
# upper-hen
# TinyGo: Getting the upper hen

This project holds all the needed code to build a monitoring system for a henhouse.

## Quickstart

Prerequisites:
- Install go, tinygo, kubectl, helm, kind

First deploy the cluster, it will take a few minutes, go get the water boiling during this time.
```bash
make deploy
```

You can test (even you do not have an Arduino board) by sending a measure:
```bash
make curl_measure
```

You should expect a 200 HTTP answer:
```bash
< HTTP/1.1 200 OK
< Date: Thu, 14 Jul 2022 17:55:02 GMT
< Content-Length: 0
< Connection: keep-alive
```

If you have an Arduino board, you can flash [this program](https://github.com/doniacld/tinygo-discovery/blob/main/tiny-hen/main.go) on your card using this command. Adjust the target to your model.

```bash
tinygo flash -target=arduino-nano33 wifinina/httppost/main.go
```

Then read from the serial port. To find it, you can use the following command, using tab to autocomplete the usb modem number:

```bash
ll /dev/cu.usbmodem1421
```

```bash
go run utils/read_serial.go -port /dev/cu.usbmodem1101
```

[//]: # ( TODO add a section about the SSID parameters in the tinygo file)

Now it should send data.

30 changes: 30 additions & 0 deletions cmd/handlers/get_hi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package handlers

import (
"encoding/json"
"log"
"net/http"
)

// GetHi is the handler for GET /hi endpoint
func GetHi(w http.ResponseWriter, r *http.Request) {
log.Println("GET /hi")

// default status code is 200
w.Header().Set("Content-Type", "application/json")

resp := make(map[string]string)
resp["greeting"] = "Cluck!"
jsonResp, err := json.Marshal(resp)
if err != nil {
log.Printf("Error happened in JSON marshal. Err: %s", err.Error())
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

_, err = w.Write(jsonResp)
if err != nil {
log.Printf("Error happened while writing response. Err: %s", err.Error())
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
37 changes: 37 additions & 0 deletions cmd/handlers/post_measure.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package handlers

import (
"encoding/json"
"log"
"net/http"

"github.com/doniacld/tiny-hen/cmd/prommetric"
)

// PostMeasureResponse is the response from PostMeasure endpoint
type PostMeasureResponse struct {
Temperature float64 `json:"temperature"`
Humidity float64 `json:"humidity"`
}

// PostMeasure is the handler for POST /measure endpoint
func PostMeasure(w http.ResponseWriter, r *http.Request) {
log.Println("POST /measure")
var measureResponse PostMeasureResponse

err := json.NewDecoder(r.Body).Decode(&measureResponse)
if err != nil {
log.Printf("Error happened in JSON unmarshal. Err: %s", err.Error())
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

// send the data to prometheus
promMeasure := prommetric.PromMeasure{
Temperature: measureResponse.Temperature,
Humidity: measureResponse.Humidity,
}
promMeasure.SetTempAndHum()

w.WriteHeader(http.StatusCreated)
}
35 changes: 35 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package main

import (
"fmt"
"net/http"

"github.com/prometheus/client_golang/prometheus/promhttp"

"github.com/doniacld/tiny-hen/cmd/handlers"
"github.com/doniacld/tiny-hen/cmd/prommetric"
)

const serverPort = ":10010"

func main() {
// register the prometheus metrics
prommetric.RegisterGauges()

fmt.Printf("Listening on port%s\n", serverPort)
mux := http.NewServeMux()

// GET /hi
mux.HandleFunc("/hi", handlers.GetHi)

// POST /measure
mux.HandleFunc("/measure", handlers.PostMeasure)

// GET /metrics
mux.Handle("/metrics", promhttp.Handler())

err := http.ListenAndServe(serverPort, mux)
if err != nil {
panic(err)
}
}
38 changes: 38 additions & 0 deletions cmd/prommetric/metric.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package prommetric

import (
"fmt"
"time"

"github.com/prometheus/client_golang/prometheus"
)

type PromMeasure struct {
Temperature float64 `json:"temperature"`
Humidity float64 `json:"humidity"`
}

var (
TempGauge = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "temperature_celsius",
Help: "The temperature of the hen house in celsius.",
})

HumGauge = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "humidity_percent",
Help: "The humidity of the hen house in percent.",
})
)

func RegisterGauges() {
prometheus.MustRegister(TempGauge)
prometheus.MustRegister(HumGauge)
}

func (m PromMeasure) SetTempAndHum() {
TempGauge.Set(m.Temperature)
HumGauge.Set(m.Humidity)

fmt.Printf("%s: SetTempAndHum set values: Temperature: %f °C, Humidity: %f %%\n",
time.Now(), m.Temperature, m.Humidity)
}
Loading

0 comments on commit d123e78

Please sign in to comment.