parent
4b3f6c0d72
commit
41d558488e
@ -0,0 +1,60 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
# Controls when the action will run. Triggers the workflow on push to master or development
|
||||||
|
# with a tag like v1.0.0 or v1.0.0-dev
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- v[0-9]+.[0-9]+.[0-9]+
|
||||||
|
- v[0-9]+.[0-9]+.[0-9]+-[a-zA-Z]+
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||||
|
steps:
|
||||||
|
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Get Version
|
||||||
|
id: get_version
|
||||||
|
uses: battila7/get-version-action@v2.0.0
|
||||||
|
|
||||||
|
- name: install buildx
|
||||||
|
id: buildx
|
||||||
|
uses: crazy-max/ghaction-docker-buildx@v1
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
|
||||||
|
- name: Docker Login
|
||||||
|
# You may pin to the exact commit or the version.
|
||||||
|
# uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
|
||||||
|
uses: docker/login-action@v1.10.0
|
||||||
|
with:
|
||||||
|
registry: ${{ secrets.DR_URL }}
|
||||||
|
# Username used to log against the Docker registry
|
||||||
|
username: ${{ secrets.DH_USERNAME }}
|
||||||
|
# Password or personal access token used to log against the Docker registry
|
||||||
|
password: ${{ secrets.DH_PASSWORD }}
|
||||||
|
# Log out from the Docker registry at the end of a job
|
||||||
|
logout: true
|
||||||
|
|
||||||
|
- name: Docker Build & Push
|
||||||
|
env:
|
||||||
|
IMAGE_TAG: ${{ steps.get_version.outputs.version-without-v }}
|
||||||
|
run: |
|
||||||
|
docker buildx build --push \
|
||||||
|
--tag ${{ secrets.DR_URL }}/weather:$IMAGE_TAG \
|
||||||
|
--platform linux/amd64,linux/arm/v7,linux/arm64 .
|
||||||
|
- name: Update deployment file
|
||||||
|
run: TAG=${{ steps.get_version.outputs.version-without-v }} && sed -i 's|<IMAGE>|${{ secrets.DR_URL }}/weather:'${TAG}'|' $GITHUB_WORKSPACE/deployment.yml
|
||||||
|
|
||||||
|
- uses: azure/k8s-set-context@v1
|
||||||
|
with:
|
||||||
|
method: kubeconfig
|
||||||
|
kubeconfig: ${{ secrets.KUBE_CONFIG }}
|
||||||
|
id: setcontext
|
||||||
|
|
||||||
|
- name: Deploy to Kubernetes
|
||||||
|
run: kubectl apply -f $GITHUB_WORKSPACE/deployment.yml
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
FROM golang:1.17-alpine as dev
|
||||||
|
|
||||||
|
WORKDIR /go/src/weather
|
||||||
|
COPY ./go.mod .
|
||||||
|
COPY ./go.sum .
|
||||||
|
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN go install ./...
|
||||||
|
|
||||||
|
CMD [ "go", "run", "cmd/weather/main.go"]
|
||||||
|
|
||||||
|
from alpine
|
||||||
|
|
||||||
|
WORKDIR /bin
|
||||||
|
|
||||||
|
COPY --from=dev /go/bin/weather ./weather
|
||||||
|
|
||||||
|
CMD [ "weather" ]
|
||||||
@ -1 +1,2 @@
|
|||||||
# weather
|
# weather
|
||||||
|
Golang server to bridge common Weather stations to MQTT and a database
|
||||||
|
|||||||
@ -0,0 +1,147 @@
|
|||||||
|
package weather
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type AmbientService interface {
|
||||||
|
Event(uint64) (*AmbientEntry, error)
|
||||||
|
AddEvent(*AmbientEntry) (*AmbientEntry, error)
|
||||||
|
UpdateEvent(*AmbientEntry) error
|
||||||
|
DeleteEvent(*AmbientEntry) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type AmbientEntry struct {
|
||||||
|
ID uint64
|
||||||
|
MAC string `schema:"MAC"`
|
||||||
|
DateUTC time.Time `schema:"dateutc"`
|
||||||
|
WindDir int `schema:"winddir"`
|
||||||
|
WindSpeedMPH float32 `schema:"windspeedmph"`
|
||||||
|
WindGustMPH float32 `schema:"windgustmph"`
|
||||||
|
WindGustDir int `schema:"windgustdir"`
|
||||||
|
MaxDailyGust float32 `schema:"maxdailygust"`
|
||||||
|
WindSpdMPH_Avg2m float32 `schema:"windspdmph_avg2m"`
|
||||||
|
WindDir_Avg2m int `schema:"winddir_avg2m"`
|
||||||
|
WindSpdMPH_Avg10m float32 `schema:"windspdmph_avg10m"`
|
||||||
|
WindDir_Avg10m int `schema:"winddir_avg10m"`
|
||||||
|
WindGustMPH_Interval int `schema:"windgustmph_interval"`
|
||||||
|
Humidity int `schema:"humidity"`
|
||||||
|
Humidity1 int `schema:"humidity1"`
|
||||||
|
Humidity2 int `schema:"humidity2"`
|
||||||
|
Humidity3 int `schema:"humidity3"`
|
||||||
|
Humidity4 int `schema:"humidity4"`
|
||||||
|
Humidity5 int `schema:"humidity5"`
|
||||||
|
Humidity6 int `schema:"humidity6"`
|
||||||
|
Humidity7 int `schema:"humidity7"`
|
||||||
|
Humidity8 int `schema:"humidity8"`
|
||||||
|
Humidity9 int `schema:"humidity9"`
|
||||||
|
Humidity10 int `schema:"humidity10"`
|
||||||
|
HumidityIn int `schema:"humidityin"`
|
||||||
|
TempF float32 `schema:"tempf"`
|
||||||
|
Temp1F float32 `schema:"temp1f"`
|
||||||
|
Temp2F float32 `schema:"temp2f"`
|
||||||
|
Temp3F float32 `schema:"temp3f"`
|
||||||
|
Temp4F float32 `schema:"temp4f"`
|
||||||
|
Temp5F float32 `schema:"temp5f"`
|
||||||
|
Temp6F float32 `schema:"temp6f"`
|
||||||
|
Temp7F float32 `schema:"temp7f"`
|
||||||
|
Temp8F float32 `schema:"temp8f"`
|
||||||
|
Temp9F float32 `schema:"temp9f"`
|
||||||
|
Temp10F float32 `schema:"temp10f"`
|
||||||
|
TempInF float32 `schema:"tempinf"`
|
||||||
|
HourlyRainIn float32 `schema:"hourlyrainin"`
|
||||||
|
DailyRainIn float32 `schema:"dailyrainin"`
|
||||||
|
Last24HourRainIn float32 `schema:"24hourrainin"`
|
||||||
|
WeeklyRainIn float32 `schema:"weeklyrainin"`
|
||||||
|
MonthlyRainIn float32 `schema:"monthlyrainin"`
|
||||||
|
YearlyRainIn float32 `schema:"yearlyrainin"`
|
||||||
|
EventRainIn float32 `schema:"eventrainin"`
|
||||||
|
TotalRainIn float32 `schema:"totalrainin"`
|
||||||
|
BaromRelIn float32 `schema:"baromrelin"`
|
||||||
|
BaromAbsIn float32 `schema:"baromabsin"`
|
||||||
|
UV int `schema:"uv"`
|
||||||
|
SolarRadiation float32 `schema:"solarradiation"`
|
||||||
|
CO2 int `schema:"co2"`
|
||||||
|
PM25 int `schema:"pm25"`
|
||||||
|
PM25_24H float32 `schema:"pm25_24h"`
|
||||||
|
PM25_In int `schema:"pm25_in"`
|
||||||
|
PM25_In_24H float32 `schema:"pm25_in_24h"`
|
||||||
|
PM10_In int `schema:"pm10_in"`
|
||||||
|
PM10_In_24H float32 `schema:"pm10_in_24h"`
|
||||||
|
CO2_In int `schema:"co2_in"`
|
||||||
|
CO2_In_24H float32 `schema:"co2_in_24h"`
|
||||||
|
PM_In_Temp float32 `schema:"pm_in_temp"`
|
||||||
|
PM_in_Humidity int `schema:"pm_in_humidity"`
|
||||||
|
Relay1 bool `schema:"relay1"`
|
||||||
|
Relay2 bool `schema:"relay2"`
|
||||||
|
Relay3 bool `schema:"relay3"`
|
||||||
|
Relay4 bool `schema:"relay4"`
|
||||||
|
Relay5 bool `schema:"relay5"`
|
||||||
|
Relay6 bool `schema:"relay6"`
|
||||||
|
Relay7 bool `schema:"relay7"`
|
||||||
|
Relay8 bool `schema:"relay8"`
|
||||||
|
Relay9 bool `schema:"relay9"`
|
||||||
|
Relay10 bool `schema:"relay10"`
|
||||||
|
SoilTemp1 float32 `schema:"soiltemp1"`
|
||||||
|
SoilTemp2 float32 `schema:"soiltemp2"`
|
||||||
|
SoilTemp3 float32 `schema:"soiltemp3"`
|
||||||
|
SoilTemp4 float32 `schema:"soiltemp4"`
|
||||||
|
SoilTemp5 float32 `schema:"soiltemp5"`
|
||||||
|
SoilTemp6 float32 `schema:"soiltemp6"`
|
||||||
|
SoilTemp7 float32 `schema:"soiltemp7"`
|
||||||
|
SoilTemp8 float32 `schema:"soiltemp8"`
|
||||||
|
SoilTemp9 float32 `schema:"soiltemp9"`
|
||||||
|
SoilTemp10 float32 `schema:"soiltemp10"`
|
||||||
|
SoilHum1 int `schema:"soilhum1"`
|
||||||
|
SoilHum2 int `schema:"soilhum2"`
|
||||||
|
SoilHum3 int `schema:"soilhum3"`
|
||||||
|
SoilHum4 int `schema:"soilhum4"`
|
||||||
|
SoilHum5 int `schema:"soilhum5"`
|
||||||
|
SoilHum6 int `schema:"soilhum6"`
|
||||||
|
SoilHum7 int `schema:"soilhum7"`
|
||||||
|
SoilHum8 int `schema:"soilhum8"`
|
||||||
|
SoilHum9 int `schema:"soilhum9"`
|
||||||
|
SoilHum10 int `schema:"soilhum10"`
|
||||||
|
Leak1 bool `schema:"leak1"`
|
||||||
|
Leak2 bool `schema:"leak2"`
|
||||||
|
Leak3 bool `schema:"leak3"`
|
||||||
|
Leak4 bool `schema:"leak4"`
|
||||||
|
Lightning_Time time.Time `schema:"lightning_time"`
|
||||||
|
Lightning_Day int `schema:"lightning_day"`
|
||||||
|
Lightning_Distance float32 `schema:"lightning_distance"`
|
||||||
|
BattOut bool `schema:"battout"`
|
||||||
|
BattIn bool `schema:"battin"`
|
||||||
|
Batt1 bool `schema:"batt1"`
|
||||||
|
Batt2 bool `schema:"batt2"`
|
||||||
|
Batt3 bool `schema:"batt3"`
|
||||||
|
Batt4 bool `schema:"batt4"`
|
||||||
|
Batt5 bool `schema:"batt5"`
|
||||||
|
Batt6 bool `schema:"batt6"`
|
||||||
|
Batt7 bool `schema:"batt7"`
|
||||||
|
Batt8 bool `schema:"batt8"`
|
||||||
|
Batt9 bool `schema:"batt9"`
|
||||||
|
Batt10 bool `schema:"batt10"`
|
||||||
|
BattR1 bool `schema:"battr1"`
|
||||||
|
BattR2 bool `schema:"battr2"`
|
||||||
|
BattR3 bool `schema:"battr3"`
|
||||||
|
BattR4 bool `schema:"battr4"`
|
||||||
|
BattR5 bool `schema:"battr5"`
|
||||||
|
BattR6 bool `schema:"battr6"`
|
||||||
|
BattR7 bool `schema:"battr7"`
|
||||||
|
BattR8 bool `schema:"battr8"`
|
||||||
|
BattR9 bool `schema:"battr9"`
|
||||||
|
BattR10 bool `schema:"battr10"`
|
||||||
|
Batt_25 bool `schema:"batt_25"`
|
||||||
|
Batt_25In bool `schema:"batt_25in"`
|
||||||
|
BatLeak1 bool `schema:"batleak1"`
|
||||||
|
BatLeak2 bool `schema:"batleak2"`
|
||||||
|
BatLeak3 bool `schema:"batleak3"`
|
||||||
|
BatLeak4 bool `schema:"batleak4"`
|
||||||
|
Batt_Lightning bool `schema:"batt_lightning"`
|
||||||
|
BattSM1 bool `schema:"battsm1"`
|
||||||
|
BattSM2 bool `schema:"battsm2"`
|
||||||
|
BattSM3 bool `schema:"battsm3"`
|
||||||
|
BattSM4 bool `schema:"battsm4"`
|
||||||
|
BattRain bool `schema:"battrain"`
|
||||||
|
BattCO2 bool `schema:"batt_co2"`
|
||||||
|
StationType string `schema:"stationtype"`
|
||||||
|
PASSKEY string `schema:"passkey"`
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
|
"github.com/dustinpianalto/weather/internal/mqtt"
|
||||||
|
"github.com/dustinpianalto/weather/internal/postgres"
|
||||||
|
"github.com/dustinpianalto/weather/pkg/endpoints"
|
||||||
|
"github.com/dustinpianalto/weather/pkg/services"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
router := mux.NewRouter()
|
||||||
|
router.HandleFunc("/data/report", endpoints.AmbientHandler)
|
||||||
|
router.HandleFunc("/data/report/", endpoints.AmbientHandler)
|
||||||
|
router.HandleFunc("/", endpoints.AmbientHandler)
|
||||||
|
|
||||||
|
dbConnString := os.Getenv("DATABASE_URL")
|
||||||
|
postgres.ConnectDatabase(dbConnString)
|
||||||
|
host := os.Getenv("MQTT_HOST")
|
||||||
|
port, err := strconv.Atoi(os.Getenv("MQTT_PORT"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
user := os.Getenv("MQTT_USER")
|
||||||
|
pass := os.Getenv("MQTT_PASSWORD")
|
||||||
|
mqtt.CreateMQTTClient(host, user, pass, port)
|
||||||
|
services.InitServices()
|
||||||
|
|
||||||
|
log.Fatal(http.ListenAndServe(":8080", router))
|
||||||
|
}
|
||||||
@ -0,0 +1,125 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: weather
|
||||||
|
namespace: weather
|
||||||
|
labels:
|
||||||
|
app: weather
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: weather
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxSurge: 1
|
||||||
|
maxUnavailable: 1
|
||||||
|
minReadySeconds: 120
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: weather
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: pgbouncer
|
||||||
|
image: timoha/pgbouncer:1.15.0
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "0.5"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "1"
|
||||||
|
env:
|
||||||
|
- name: DATABASE_URL
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: weather
|
||||||
|
key: pgbouncer_url
|
||||||
|
- name: SERVER_TLS_SSLMODE
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: weather
|
||||||
|
key: pgbouncer_ssl
|
||||||
|
- name: AUTH_TYPE
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: weather
|
||||||
|
key: pgbouncer_auth
|
||||||
|
ports:
|
||||||
|
- containerPort: 5432
|
||||||
|
- name: weather
|
||||||
|
image: <IMAGE>
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "0.5"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "1"
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
env:
|
||||||
|
- name: DATABASE_URL
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: weather
|
||||||
|
key: database_url
|
||||||
|
- name: MQTT_HOST
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: weather
|
||||||
|
key: mqtt_host
|
||||||
|
- name: MQTT_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: weather
|
||||||
|
key: mqtt_password
|
||||||
|
- name: MQTT_USER
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: weather
|
||||||
|
key: mqtt_user
|
||||||
|
- name: MQTT_PORT
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: weather
|
||||||
|
key: mqtt_port
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: registry-1
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: weather-service
|
||||||
|
namespace: weather
|
||||||
|
labels:
|
||||||
|
app: weather
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: weather
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
name: http
|
||||||
|
port: 8080
|
||||||
|
targetPort: 8080
|
||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: weather
|
||||||
|
namespace: weather
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- host: weather.djpianalto.com
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: weather-service
|
||||||
|
port:
|
||||||
|
number: 8080
|
||||||
|
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
module github.com/dustinpianalto/weather
|
||||||
|
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/dustinpianalto/errors v0.1.0
|
||||||
|
github.com/eclipse/paho.mqtt.golang v1.3.5
|
||||||
|
github.com/gorilla/mux v1.8.0
|
||||||
|
github.com/gorilla/schema v1.2.0
|
||||||
|
github.com/lib/pq v1.10.4
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gorilla/websocket v1.4.2 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 // indirect
|
||||||
|
)
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
github.com/dustinpianalto/errors v0.1.0 h1:1wG0dhtE1w0u3+QRrQnR6vRO3QrVGpqIEP/0X83i4f4=
|
||||||
|
github.com/dustinpianalto/errors v0.1.0/go.mod h1:Fo865gGhrM1eyVIp5H5U8kQkZtFc/daiU3QBpUCd+B4=
|
||||||
|
github.com/eclipse/paho.mqtt.golang v1.3.5 h1:sWtmgNxYM9P2sP+xEItMozsR3w0cqZFlqnNN1bdl41Y=
|
||||||
|
github.com/eclipse/paho.mqtt.golang v1.3.5/go.mod h1:eTzb4gxwwyWpqBUHGQZ4ABAV7+Jgm1PklsYT/eo8Hcc=
|
||||||
|
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||||
|
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
|
github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc=
|
||||||
|
github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
|
||||||
|
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||||
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
|
||||||
|
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 h1:Jcxah/M+oLZ/R4/z5RzfPzGbPXnVDPkEDtf2JnuxN+U=
|
||||||
|
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
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=
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
package mqtt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/dustinpianalto/errors"
|
||||||
|
"github.com/dustinpianalto/weather"
|
||||||
|
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
AmbientService weather.AmbientService
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateMQTTClient(host, username, password string, port int) {
|
||||||
|
opts := mqtt.NewClientOptions()
|
||||||
|
opts.AddBroker(fmt.Sprintf("tcp://%s:%d", host, port))
|
||||||
|
opts.SetClientID("weather_bridge")
|
||||||
|
opts.SetUsername(username)
|
||||||
|
opts.SetPassword(password)
|
||||||
|
opts.OnConnect = connectHandler
|
||||||
|
opts.OnConnectionLost = connectionLostHandler
|
||||||
|
client := mqtt.NewClient(opts)
|
||||||
|
log.Println("mqtt client created")
|
||||||
|
token := client.Connect()
|
||||||
|
if token.Wait() && token.Error() != nil {
|
||||||
|
log.Println(token.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
initServices(&client)
|
||||||
|
log.Println("mqtt client initalized")
|
||||||
|
}
|
||||||
|
|
||||||
|
func connectHandler(client mqtt.Client) {
|
||||||
|
log.Println("MQTT Connected")
|
||||||
|
}
|
||||||
|
|
||||||
|
func connectionLostHandler(client mqtt.Client, err error) {
|
||||||
|
const method string = "mqtt/connectionLostHandler"
|
||||||
|
log.Println(errors.E(method, errors.Internal, "MQTT Connection Lost", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func initServices(client *mqtt.Client) {
|
||||||
|
AmbientService = eventService{client: client}
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
package mqtt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/dustinpianalto/weather"
|
||||||
|
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||||
|
)
|
||||||
|
|
||||||
|
type eventService struct {
|
||||||
|
client *mqtt.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventService) Event(i uint64) (*weather.AmbientEntry, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventService) AddEvent(event *weather.AmbientEntry) (*weather.AmbientEntry, error) {
|
||||||
|
m := eventToMap(event)
|
||||||
|
for k, v := range m {
|
||||||
|
(*e.client).Publish(fmt.Sprintf("weather/WS-2920C/%s", k), 0, false, v)
|
||||||
|
}
|
||||||
|
return event, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventService) UpdateEvent(event *weather.AmbientEntry) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventService) DeleteEvent(event *weather.AmbientEntry) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func eventToMap(event *weather.AmbientEntry) map[string]string {
|
||||||
|
m := make(map[string]string)
|
||||||
|
iVal := reflect.ValueOf(event).Elem()
|
||||||
|
typ := iVal.Type()
|
||||||
|
for i := 0; i < iVal.NumField(); i++ {
|
||||||
|
f := iVal.Field(i)
|
||||||
|
var v string
|
||||||
|
switch f.Interface().(type) {
|
||||||
|
case int, int8, int16, int32, int64:
|
||||||
|
v = strconv.FormatInt(f.Int(), 10)
|
||||||
|
case uint, uint8, uint16, uint32, uint64:
|
||||||
|
v = strconv.FormatUint(f.Uint(), 10)
|
||||||
|
case float32:
|
||||||
|
v = strconv.FormatFloat(f.Float(), 'f', 4, 32)
|
||||||
|
case float64:
|
||||||
|
v = strconv.FormatFloat(f.Float(), 'f', 4, 64)
|
||||||
|
case []byte:
|
||||||
|
v = string(f.Bytes())
|
||||||
|
case string:
|
||||||
|
v = f.String()
|
||||||
|
case bool:
|
||||||
|
if f.Bool() {
|
||||||
|
v = "true"
|
||||||
|
} else {
|
||||||
|
v = "false"
|
||||||
|
}
|
||||||
|
case time.Time:
|
||||||
|
v = strconv.FormatInt(f.Interface().(time.Time).Unix(), 10)
|
||||||
|
}
|
||||||
|
m[typ.Field(i).Name] = v
|
||||||
|
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package postgres
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/dustinpianalto/weather"
|
||||||
|
_ "github.com/lib/pq"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
EventService weather.AmbientService
|
||||||
|
)
|
||||||
|
|
||||||
|
func ConnectDatabase(dbConnString string) {
|
||||||
|
db, err := sql.Open("postgres", dbConnString)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Can't connect to the database. %v", err))
|
||||||
|
}
|
||||||
|
db.SetMaxOpenConns(75) // The RDS instance has a max of 75 open connections
|
||||||
|
db.SetMaxIdleConns(5)
|
||||||
|
db.SetConnMaxLifetime(300)
|
||||||
|
log.Println("Database Connected")
|
||||||
|
initServices(db)
|
||||||
|
log.Println("Postgres Database Initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
func initServices(db *sql.DB) {
|
||||||
|
EventService = eventService{db: db}
|
||||||
|
}
|
||||||
@ -0,0 +1,173 @@
|
|||||||
|
package postgres
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
|
"github.com/dustinpianalto/weather"
|
||||||
|
)
|
||||||
|
|
||||||
|
type eventService struct {
|
||||||
|
db *sql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventService) Event(i uint64) (*weather.AmbientEntry, error) {
|
||||||
|
queryString := `SELECT
|
||||||
|
mac, dateutc, winddir, windspeedmph, windgustmph, windgustdir, maxdailygust,
|
||||||
|
windspdmph_avg2m, winddir_avg2m, windspdmph_avg10m, winddir_avg10m, windgustmph_interval,
|
||||||
|
humidity, humidity1, humidity2, humidity3, humidity4, humidity5, humidity6, humidity7,
|
||||||
|
humidity8, humidity9, humidity10, humidityin, tempf, temp1f, temp2f, temp3f, temp4f, temp5f,
|
||||||
|
temp6f, temp7f, temp8f, temp9f, temp10f, tempinf, hourlyrainin, dailyrainin, last24hourrainin,
|
||||||
|
weeklyrainin, monthlyrainin, yearlyrainin, eventrainin, totalrainin, baromrelin, baromabsin,
|
||||||
|
uv, solarradiation, co2, pm25, pm25_24h, pm25_in, pm25_in_24h, pm10_in, pm10_in_24h, co2_in,
|
||||||
|
co2_in_24h, pm_in_temp, pm_in_humidity, relay1, relay2, relay3, relay4, relay5, relay6,
|
||||||
|
relay7, relay8, relay9, relay10, soiltemp1, soiltemp2, soiltemp3, soiltemp4, soiltemp5,
|
||||||
|
soiltemp6, soiltemp7, soiltemp8, soiltemp9, soiltemp10, soilhum1, soilhum2, soilhum3, soilhum4,
|
||||||
|
soilhum5, soilhum6, soilhum7, soilhum8, soilhum9, soilhum10, leak1, leak2, leak3, leak4,
|
||||||
|
lightning_time, lightning_day, lightning_distance, battout, battin, batt1, batt2, batt3, batt4,
|
||||||
|
batt5, batt6, batt7, batt8, batt9, batt10, battr1, battr2, battr3, battr4, battr5, battr6,
|
||||||
|
battr7, battr8, battr9, battr10, batt_25, batt_25in, batleak1, batleak2, batleak3, batleak4,
|
||||||
|
batt_lightning, battsm1, battsm2, battsm3, battsm4, battrain, batt_co2, stationtype, passkey
|
||||||
|
FROM events WHERE id = $1`
|
||||||
|
event := weather.AmbientEntry{
|
||||||
|
ID: i,
|
||||||
|
}
|
||||||
|
err := e.db.QueryRow(queryString, i).Scan(
|
||||||
|
&event.MAC, &event.DateUTC, &event.WindDir, &event.WindSpeedMPH, &event.WindGustMPH,
|
||||||
|
&event.WindGustDir, &event.MaxDailyGust, &event.WindSpdMPH_Avg2m, &event.WindDir_Avg2m,
|
||||||
|
&event.WindSpdMPH_Avg10m, &event.WindDir_Avg10m, &event.WindGustMPH_Interval, &event.Humidity,
|
||||||
|
&event.Humidity1, &event.Humidity2, &event.Humidity3, &event.Humidity4, &event.Humidity5,
|
||||||
|
&event.Humidity6, &event.Humidity7, &event.Humidity8, &event.Humidity9, &event.Humidity10,
|
||||||
|
&event.HumidityIn, &event.TempF, &event.Temp1F, &event.Temp2F, &event.Temp3F, &event.Temp4F,
|
||||||
|
&event.Temp5F, &event.Temp6F, &event.Temp7F, &event.Temp8F, &event.Temp9F, &event.Temp10F,
|
||||||
|
&event.TempInF, &event.HourlyRainIn, &event.DailyRainIn, &event.Last24HourRainIn,
|
||||||
|
&event.WeeklyRainIn, &event.MonthlyRainIn, &event.YearlyRainIn, &event.EventRainIn,
|
||||||
|
&event.TotalRainIn, &event.BaromRelIn, &event.BaromAbsIn, &event.UV, &event.SolarRadiation,
|
||||||
|
&event.CO2, &event.PM25, &event.PM25_24H, &event.PM25_In, &event.PM25_In_24H, &event.PM10_In,
|
||||||
|
&event.PM10_In_24H, &event.CO2_In, &event.CO2_In_24H, &event.PM_In_Temp, &event.PM_in_Humidity,
|
||||||
|
&event.Relay1, &event.Relay2, &event.Relay3, &event.Relay4, &event.Relay5, &event.Relay6,
|
||||||
|
&event.Relay7, &event.Relay8, &event.Relay9, &event.Relay10, &event.SoilTemp1, &event.SoilTemp2,
|
||||||
|
&event.SoilTemp3, &event.SoilTemp4, &event.SoilTemp5, &event.SoilTemp6, &event.SoilTemp7,
|
||||||
|
&event.SoilTemp8, &event.SoilTemp9, &event.SoilTemp10, &event.SoilHum1, &event.SoilHum2,
|
||||||
|
&event.SoilHum3, &event.SoilHum4, &event.SoilHum5, &event.SoilHum6, &event.SoilHum7,
|
||||||
|
&event.SoilHum8, &event.SoilHum9, &event.SoilHum10, &event.Leak1, &event.Leak2, &event.Leak3,
|
||||||
|
&event.Leak4, &event.Lightning_Time, &event.Lightning_Day, &event.Lightning_Distance,
|
||||||
|
&event.BattOut, &event.BattIn, &event.Batt1, &event.Batt2, &event.Batt3, &event.Batt4,
|
||||||
|
&event.Batt5, &event.Batt6, &event.Batt7, &event.Batt8, &event.Batt9, &event.Batt10,
|
||||||
|
&event.BattR1, &event.BattR2, &event.BattR3, &event.BattR4, &event.BattR5, &event.BattR6,
|
||||||
|
&event.BattR7, &event.BattR8, &event.BattR9, &event.BattR10, &event.Batt_25, &event.Batt_25In,
|
||||||
|
&event.BatLeak1, &event.BatLeak2, &event.BatLeak3, &event.BatLeak4, &event.Batt_Lightning,
|
||||||
|
&event.BattSM1, &event.BattSM2, &event.BattSM3, &event.BattSM4, &event.BattRain, &event.BattCO2,
|
||||||
|
&event.StationType, &event.PASSKEY)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &event, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventService) AddEvent(event *weather.AmbientEntry) (*weather.AmbientEntry, error) {
|
||||||
|
queryString := `INSERT INTO events
|
||||||
|
(mac, dateutc, winddir, windspeedmph, windgustmph, windgustdir, maxdailygust,
|
||||||
|
windspdmph_avg2m, winddir_avg2m, windspdmph_avg10m, winddir_avg10m, windgustmph_interval,
|
||||||
|
humidity, humidity1, humidity2, humidity3, humidity4, humidity5, humidity6, humidity7,
|
||||||
|
humidity8, humidity9, humidity10, humidityin, tempf, temp1f, temp2f, temp3f, temp4f,
|
||||||
|
temp5f, temp6f, temp7f, temp8f, temp9f, temp10f, tempinf, hourlyrainin, dailyrainin,
|
||||||
|
last24hourrainin, weeklyrainin, monthlyrainin, yearlyrainin, eventrainin, totalrainin, baromrelin,
|
||||||
|
baromabsin, uv, solarradiation, co2, pm25, pm25_24h, pm25_in, pm25_in_24h, pm10_in, pm10_in_24h,
|
||||||
|
co2_in, co2_in_24h, pm_in_temp, pm_in_humidity, relay1, relay2, relay3, relay4, relay5, relay6,
|
||||||
|
relay7, relay8, relay9, relay10, soiltemp1, soiltemp2, soiltemp3, soiltemp4, soiltemp5, soiltemp6,
|
||||||
|
soiltemp7, soiltemp8, soiltemp9, soiltemp10, soilhum1, soilhum2, soilhum3, soilhum4, soilhum5,
|
||||||
|
soilhum6, soilhum7, soilhum8, soilhum9, soilhum10, leak1, leak2, leak3, leak4, lightning_time,
|
||||||
|
lightning_day, lightning_distance, battout, battin, batt1, batt2, batt3, batt4, batt5, batt6,
|
||||||
|
batt7, batt8, batt9, batt10, battr1, battr2, battr3, battr4, battr5, battr6, battr7, battr8,
|
||||||
|
battr9, battr10, batt_25, batt_25in, batleak1, batleak2, batleak3, batleak4, batt_lightning,
|
||||||
|
battsm1, battsm2, battsm3, battsm4, battrain, batt_co2, stationtype, passkey)
|
||||||
|
VALUES
|
||||||
|
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21,
|
||||||
|
$22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39, $40,
|
||||||
|
$41, $42, $43, $44, $45, $46, $47, $48, $49, $50, $51, $52, $53, $54, $55, $56, $57, $58, $59,
|
||||||
|
$60, $61, $62, $63, $64, $65, $66, $67, $68, $69, $70, $71, $72, $73, $74, $75, $76, $77, $78,
|
||||||
|
$79, $80, $81, $82, $83, $84, $85, $86, $87, $88, $89, $90, $91, $92, $93, $94, $95, $96, $97,
|
||||||
|
$98, $99, $100, $101, $102, $103, $104, $105, $106, $107, $108, $109, $110, $111, $112, $113,
|
||||||
|
$114, $115, $116, $117, $118, $119, $120, $121, $122, $123, $124, $125, $126, $127, $128, $129,
|
||||||
|
$130, $131, $132, $133)
|
||||||
|
RETURNING id`
|
||||||
|
err := e.db.QueryRow(queryString, event.MAC, event.DateUTC, event.WindDir, event.WindSpeedMPH,
|
||||||
|
event.WindGustMPH, event.WindGustDir, event.MaxDailyGust, event.WindSpdMPH_Avg2m, event.WindDir_Avg2m,
|
||||||
|
event.WindSpdMPH_Avg10m, event.WindDir_Avg10m, event.WindGustMPH_Interval, event.Humidity,
|
||||||
|
event.Humidity1, event.Humidity2, event.Humidity3, event.Humidity4, event.Humidity5, event.Humidity6,
|
||||||
|
event.Humidity7, event.Humidity8, event.Humidity9, event.Humidity10, event.HumidityIn, event.TempF,
|
||||||
|
event.Temp1F, event.Temp2F, event.Temp3F, event.Temp4F, event.Temp5F, event.Temp6F, event.Temp7F,
|
||||||
|
event.Temp8F, event.Temp9F, event.Temp10F, event.TempInF, event.HourlyRainIn, event.DailyRainIn,
|
||||||
|
event.Last24HourRainIn, event.WeeklyRainIn, event.MonthlyRainIn, event.YearlyRainIn, event.EventRainIn,
|
||||||
|
event.TotalRainIn, event.BaromRelIn, event.BaromAbsIn, event.UV, event.SolarRadiation, event.CO2,
|
||||||
|
event.PM25, event.PM25_24H, event.PM25_In, event.PM25_In_24H, event.PM10_In, event.PM10_In_24H,
|
||||||
|
event.CO2_In, event.CO2_In_24H, event.PM_In_Temp, event.PM_in_Humidity, event.Relay1, event.Relay2,
|
||||||
|
event.Relay3, event.Relay4, event.Relay5, event.Relay6, event.Relay7, event.Relay8, event.Relay9,
|
||||||
|
event.Relay10, event.SoilTemp1, event.SoilTemp2, event.SoilTemp3, event.SoilTemp4, event.SoilTemp5,
|
||||||
|
event.SoilTemp6, event.SoilTemp7, event.SoilTemp8, event.SoilTemp9, event.SoilTemp10, event.SoilHum1,
|
||||||
|
event.SoilHum2, event.SoilHum3, event.SoilHum4, event.SoilHum5, event.SoilHum6, event.SoilHum7,
|
||||||
|
event.SoilHum8, event.SoilHum9, event.SoilHum10, event.Leak1, event.Leak2, event.Leak3, event.Leak4,
|
||||||
|
event.Lightning_Time, event.Lightning_Day, event.Lightning_Distance, event.BattOut, event.BattIn,
|
||||||
|
event.Batt1, event.Batt2, event.Batt3, event.Batt4, event.Batt5, event.Batt6, event.Batt7, event.Batt8,
|
||||||
|
event.Batt9, event.Batt10, event.BattR1, event.BattR2, event.BattR3, event.BattR4, event.BattR5,
|
||||||
|
event.BattR6, event.BattR7, event.BattR8, event.BattR9, event.BattR10, event.Batt_25, event.Batt_25In,
|
||||||
|
event.BatLeak1, event.BatLeak2, event.BatLeak3, event.BatLeak4, event.Batt_Lightning, event.BattSM1,
|
||||||
|
event.BattSM2, event.BattSM3, event.BattSM4, event.BattRain, event.BattCO2, event.StationType,
|
||||||
|
event.PASSKEY).Scan(&event.ID)
|
||||||
|
return event, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventService) UpdateEvent(event *weather.AmbientEntry) error {
|
||||||
|
queryString := `UPDATE events SET
|
||||||
|
mac = $2, dateutc = $3, winddir = $4, windspeedmph = $5, windgustmph = $6, windgustdir = $7,
|
||||||
|
maxdailygust = $8, windspdmph_avg2m = $9, winddir_avg2m = $10, windspdmph_avg10m = $11, winddir_avg10m = $12,
|
||||||
|
windgustmph_interval = $13, humidity = $14, humidity1 = $15, humidity2 = $16, humidity3 = $17, humidity4 = $18,
|
||||||
|
humidity5 = $19, humidity6 = $20, humidity7 = $21, humidity8 = $22, humidity9 = $23, humidity10 = $24,
|
||||||
|
humidityin = $25, tempf = $26, temp1f = $27, temp2f = $28, temp3f = $29, temp4f = $30, temp5f = $31,
|
||||||
|
temp6f = $32, temp7f = $33, temp8f = $34, temp9f = $35, temp10f = $36, tempinf = $37, hourlyrainin = $38,
|
||||||
|
dailyrainin = $39, last24hourrainin = $40, weeklyrainin = $41, monthlyrainin = $42, yearlyrainin = $43,
|
||||||
|
eventrainin = $44, totalrainin = $45, baromrelin = $46, baromabsin = $47, uv = $48, solarradiation = $49,
|
||||||
|
co2 = $50, pm25 = $51, pm25_24h = $52, pm25_in = $53, pm25_in_24h = $54, pm10_in = $55, pm10_in_24h = $56,
|
||||||
|
co2_in = $57, co2_in_24h = $58, pm_in_temp = $59, pm_in_humidity = $60, relay1 = $61, relay2 = $62,
|
||||||
|
relay3 = $63, relay4 = $64, relay5 = $65, relay6 = $66, relay7 = $67, relay8 = $68, relay9 = $69,
|
||||||
|
relay10 = $70, soiltemp1 = $71, soiltemp2 = $72, soiltemp3 = $73, soiltemp4 = $74, soiltemp5 = $75,
|
||||||
|
soiltemp6 = $76, soiltemp7 = $77, soiltemp8 = $78, soiltemp9 = $79, soiltemp10 = $80, soilhum1 = $81,
|
||||||
|
soilhum2 = $82, soilhum3 = $83, soilhum4 = $84, soilhum5 = $85, soilhum6 = $86, soilhum7 = $87,
|
||||||
|
soilhum8 = $88, soilhum9 = $89, soilhum10 = $90, leak1 = $91, leak2 = $92, leak3 = $93, leak4 = $94,
|
||||||
|
lightning_time = $95, lightning_day = $96, lightning_distance = $97, battout = $98, battin = $99,
|
||||||
|
batt1 = $100, batt2 = $101, batt3 = $102, batt4 = $103, batt5 = $104, batt6 = $105, batt7 = $106,
|
||||||
|
batt8 = $107, batt9 = $108, batt10 = $109, battr1 = $110, battr2 = $111, battr3 = $112, battr4 = $113,
|
||||||
|
battr5 = $114, battr6 = $115, battr7 = $116, battr8 = $117, battr9 = $118, battr10 = $119, batt_25 = $120,
|
||||||
|
batt_25in = $121, batleak1 = $122, batleak2 = $123, batleak3 = $124, batleak4 = $125, batt_lightning = $126,
|
||||||
|
battsm1 = $127, battsm2 = $128, battsm3 = $129, battsm4 = $130, battrain = $131, batt_co2 = $132,
|
||||||
|
stationtype = $133, passkey = $134, WHERE id = $1`
|
||||||
|
_, err := e.db.Exec(queryString, event.ID, event.MAC, event.DateUTC, event.WindDir, event.WindSpeedMPH,
|
||||||
|
event.WindGustMPH, event.WindGustDir, event.MaxDailyGust, event.WindSpdMPH_Avg2m, event.WindDir_Avg2m,
|
||||||
|
event.WindSpdMPH_Avg10m, event.WindDir_Avg10m, event.WindGustMPH_Interval, event.Humidity, event.Humidity1,
|
||||||
|
event.Humidity2, event.Humidity3, event.Humidity4, event.Humidity5, event.Humidity6, event.Humidity7,
|
||||||
|
event.Humidity8, event.Humidity9, event.Humidity10, event.HumidityIn, event.TempF, event.Temp1F,
|
||||||
|
event.Temp2F, event.Temp3F, event.Temp4F, event.Temp5F, event.Temp6F, event.Temp7F, event.Temp8F,
|
||||||
|
event.Temp9F, event.Temp10F, event.TempInF, event.HourlyRainIn, event.DailyRainIn, event.Last24HourRainIn,
|
||||||
|
event.WeeklyRainIn, event.MonthlyRainIn, event.YearlyRainIn, event.EventRainIn, event.TotalRainIn,
|
||||||
|
event.BaromRelIn, event.BaromAbsIn, event.UV, event.SolarRadiation, event.CO2, event.PM25, event.PM25_24H,
|
||||||
|
event.PM25_In, event.PM25_In_24H, event.PM10_In, event.PM10_In_24H, event.CO2_In, event.CO2_In_24H,
|
||||||
|
event.PM_In_Temp, event.PM_in_Humidity, event.Relay1, event.Relay2, event.Relay3, event.Relay4, event.Relay5,
|
||||||
|
event.Relay6, event.Relay7, event.Relay8, event.Relay9, event.Relay10, event.SoilTemp1, event.SoilTemp2,
|
||||||
|
event.SoilTemp3, event.SoilTemp4, event.SoilTemp5, event.SoilTemp6, event.SoilTemp7, event.SoilTemp8,
|
||||||
|
event.SoilTemp9, event.SoilTemp10, event.SoilHum1, event.SoilHum2, event.SoilHum3, event.SoilHum4,
|
||||||
|
event.SoilHum5, event.SoilHum6, event.SoilHum7, event.SoilHum8, event.SoilHum9, event.SoilHum10,
|
||||||
|
event.Leak1, event.Leak2, event.Leak3, event.Leak4, event.Lightning_Time, event.Lightning_Day,
|
||||||
|
event.Lightning_Distance, event.BattOut, event.BattIn, event.Batt1, event.Batt2, event.Batt3, event.Batt4,
|
||||||
|
event.Batt5, event.Batt6, event.Batt7, event.Batt8, event.Batt9, event.Batt10, event.BattR1, event.BattR2,
|
||||||
|
event.BattR3, event.BattR4, event.BattR5, event.BattR6, event.BattR7, event.BattR8, event.BattR9,
|
||||||
|
event.BattR10, event.Batt_25, event.Batt_25In, event.BatLeak1, event.BatLeak2, event.BatLeak3, event.BatLeak4,
|
||||||
|
event.Batt_Lightning, event.BattSM1, event.BattSM2, event.BattSM3, event.BattSM4, event.BattRain,
|
||||||
|
event.BattCO2, event.StationType, event.PASSKEY)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventService) DeleteEvent(event *weather.AmbientEntry) error {
|
||||||
|
queryString := "DELETE FROM events WHERE id = $1"
|
||||||
|
_, err := e.db.Exec(queryString, event.ID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
@ -0,0 +1,136 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS events (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
mac char(17) not null,
|
||||||
|
dateutc timestamp not null,
|
||||||
|
winddir integer,
|
||||||
|
windspeedmph float,
|
||||||
|
windgustmph float,
|
||||||
|
windgustdir integer,
|
||||||
|
maxdailygust float,
|
||||||
|
windspdmph_avg2m float,
|
||||||
|
winddir_avg2m integer,
|
||||||
|
windspdmph_avg10m float,
|
||||||
|
winddir_avg10m integer,
|
||||||
|
windgustmph_interval integer,
|
||||||
|
humidity integer,
|
||||||
|
humidity1 integer,
|
||||||
|
humidity2 integer,
|
||||||
|
humidity3 integer,
|
||||||
|
humidity4 integer,
|
||||||
|
humidity5 integer,
|
||||||
|
humidity6 integer,
|
||||||
|
humidity7 integer,
|
||||||
|
humidity8 integer,
|
||||||
|
humidity9 integer,
|
||||||
|
humidity10 integer,
|
||||||
|
humidityin integer,
|
||||||
|
tempf float,
|
||||||
|
temp1f float,
|
||||||
|
temp2f float,
|
||||||
|
temp3f float,
|
||||||
|
temp4f float,
|
||||||
|
temp5f float,
|
||||||
|
temp6f float,
|
||||||
|
temp7f float,
|
||||||
|
temp8f float,
|
||||||
|
temp9f float,
|
||||||
|
temp10f float,
|
||||||
|
tempinf float,
|
||||||
|
hourlyrainin float,
|
||||||
|
dailyrainin float,
|
||||||
|
last24hourrainin float,
|
||||||
|
weeklyrainin float,
|
||||||
|
monthlyrainin float,
|
||||||
|
yearlyrainin float,
|
||||||
|
eventrainin float,
|
||||||
|
totalrainin float,
|
||||||
|
baromrelin float,
|
||||||
|
baromabsin float,
|
||||||
|
uv integer,
|
||||||
|
solarradiation float,
|
||||||
|
co2 integer,
|
||||||
|
pm25 integer,
|
||||||
|
pm25_24h float,
|
||||||
|
pm25_in integer,
|
||||||
|
pm25_in_24h float,
|
||||||
|
pm10_in integer,
|
||||||
|
pm10_in_24h float,
|
||||||
|
co2_in integer,
|
||||||
|
co2_in_24h float,
|
||||||
|
pm_in_temp float,
|
||||||
|
pm_in_humidity integer,
|
||||||
|
relay1 boolean,
|
||||||
|
relay2 boolean,
|
||||||
|
relay3 boolean,
|
||||||
|
relay4 boolean,
|
||||||
|
relay5 boolean,
|
||||||
|
relay6 boolean,
|
||||||
|
relay7 boolean,
|
||||||
|
relay8 boolean,
|
||||||
|
relay9 boolean,
|
||||||
|
relay10 boolean,
|
||||||
|
soiltemp1 float,
|
||||||
|
soiltemp2 float,
|
||||||
|
soiltemp3 float,
|
||||||
|
soiltemp4 float,
|
||||||
|
soiltemp5 float,
|
||||||
|
soiltemp6 float,
|
||||||
|
soiltemp7 float,
|
||||||
|
soiltemp8 float,
|
||||||
|
soiltemp9 float,
|
||||||
|
soiltemp10 float,
|
||||||
|
soilhum1 integer,
|
||||||
|
soilhum2 integer,
|
||||||
|
soilhum3 integer,
|
||||||
|
soilhum4 integer,
|
||||||
|
soilhum5 integer,
|
||||||
|
soilhum6 integer,
|
||||||
|
soilhum7 integer,
|
||||||
|
soilhum8 integer,
|
||||||
|
soilhum9 integer,
|
||||||
|
soilhum10 integer,
|
||||||
|
leak1 boolean,
|
||||||
|
leak2 boolean,
|
||||||
|
leak3 boolean,
|
||||||
|
leak4 boolean,
|
||||||
|
lightning_time timestamp,
|
||||||
|
lightning_day integer,
|
||||||
|
lightning_distance float,
|
||||||
|
battout boolean,
|
||||||
|
battin boolean,
|
||||||
|
batt1 boolean,
|
||||||
|
batt2 boolean,
|
||||||
|
batt3 boolean,
|
||||||
|
batt4 boolean,
|
||||||
|
batt5 boolean,
|
||||||
|
batt6 boolean,
|
||||||
|
batt7 boolean,
|
||||||
|
batt8 boolean,
|
||||||
|
batt9 boolean,
|
||||||
|
batt10 boolean,
|
||||||
|
battr1 boolean,
|
||||||
|
battr2 boolean,
|
||||||
|
battr3 boolean,
|
||||||
|
battr4 boolean,
|
||||||
|
battr5 boolean,
|
||||||
|
battr6 boolean,
|
||||||
|
battr7 boolean,
|
||||||
|
battr8 boolean,
|
||||||
|
battr9 boolean,
|
||||||
|
battr10 boolean,
|
||||||
|
batt_25 boolean,
|
||||||
|
batt_25in boolean,
|
||||||
|
batleak1 boolean,
|
||||||
|
batleak2 boolean,
|
||||||
|
batleak3 boolean,
|
||||||
|
batleak4 boolean,
|
||||||
|
batt_lightning boolean,
|
||||||
|
battsm1 boolean,
|
||||||
|
battsm2 boolean,
|
||||||
|
battsm3 boolean,
|
||||||
|
battsm4 boolean,
|
||||||
|
battrain boolean,
|
||||||
|
batt_co2 boolean,
|
||||||
|
stationtype varchar(30),
|
||||||
|
passkey char(17)
|
||||||
|
);
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
package endpoints
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/dustinpianalto/errors"
|
||||||
|
"github.com/dustinpianalto/weather"
|
||||||
|
"github.com/dustinpianalto/weather/pkg/services"
|
||||||
|
"github.com/gorilla/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AmbientHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
const method errors.Method = "endpoints/AmbientHandler"
|
||||||
|
entry := &weather.AmbientEntry{}
|
||||||
|
decoder := schema.NewDecoder()
|
||||||
|
decoder.RegisterConverter(time.Time{}, timeConverter)
|
||||||
|
if err := decoder.Decode(entry, r.URL.Query()); err != nil {
|
||||||
|
log.Println(errors.E(method, errors.Malformed, "error decoding AmbientEntry", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if entry.MAC == "" && entry.PASSKEY != "" {
|
||||||
|
entry.MAC = entry.PASSKEY
|
||||||
|
}
|
||||||
|
entry, err := services.EventService.AddEvent(entry)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(errors.E(method, errors.Internal, "error adding entry to database", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("%#v\n\n", entry)
|
||||||
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write([]byte{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func timeConverter(value string) reflect.Value {
|
||||||
|
if v, err := time.Parse("2006-01-02 15:04:05", value); err == nil {
|
||||||
|
return reflect.ValueOf(v)
|
||||||
|
} else if i, err := strconv.ParseInt(value, 10, 64); err == nil {
|
||||||
|
return reflect.ValueOf(time.Unix(i, 0))
|
||||||
|
}
|
||||||
|
return reflect.Value{}
|
||||||
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/dustinpianalto/weather"
|
||||||
|
"github.com/dustinpianalto/weather/internal/mqtt"
|
||||||
|
"github.com/dustinpianalto/weather/internal/postgres"
|
||||||
|
)
|
||||||
|
|
||||||
|
var EventService weather.AmbientService
|
||||||
|
|
||||||
|
func InitServices() {
|
||||||
|
EventService = eventService{
|
||||||
|
postgesService: postgres.EventService,
|
||||||
|
mqttService: mqtt.AmbientService,
|
||||||
|
}
|
||||||
|
log.Println("Services Initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
type eventService struct {
|
||||||
|
postgesService weather.AmbientService
|
||||||
|
mqttService weather.AmbientService
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventService) Event(i uint64) (*weather.AmbientEntry, error) {
|
||||||
|
return e.postgesService.Event(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventService) AddEvent(event *weather.AmbientEntry) (*weather.AmbientEntry, error) {
|
||||||
|
event, err := e.postgesService.AddEvent(event)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
event, err = e.mqttService.AddEvent(event)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
return event, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventService) UpdateEvent(event *weather.AmbientEntry) error {
|
||||||
|
return e.postgesService.UpdateEvent(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventService) DeleteEvent(event *weather.AmbientEntry) error {
|
||||||
|
return e.postgesService.UpdateEvent(event)
|
||||||
|
}
|
||||||
Loading…
Reference in new issue