157 lines
4.4 KiB
Go
157 lines
4.4 KiB
Go
package pooRecorder
|
|
|
|
import (
|
|
"bytes"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/spf13/viper"
|
|
"github.com/t-liu93/home-automation-backend/util/notion"
|
|
"golang.org/x/exp/slog"
|
|
)
|
|
|
|
type recordDetail struct {
|
|
Status string `json:"status"`
|
|
Latitude string `json:"latitude"`
|
|
Longitude string `json:"longitude"`
|
|
}
|
|
|
|
type pooStatusHttpSensorAttributes struct {
|
|
LastPoo string `json:"last_poo"`
|
|
}
|
|
|
|
type pooStatusHttpSensor struct {
|
|
EntityId string `json:"entity_id"`
|
|
State string `json:"state"`
|
|
Attributes pooStatusHttpSensorAttributes `json:"attributes"`
|
|
}
|
|
|
|
var (
|
|
db *sql.DB
|
|
)
|
|
|
|
func publishPooStatus(pooStatus pooStatusHttpSensor) {
|
|
if viper.InConfig("pooRecorder.homeassistantIp") &&
|
|
viper.InConfig("pooRecorder.homeassistantPort") &&
|
|
viper.InConfig("pooRecorder.homeassistantToken") {
|
|
homeAssistantIp := viper.GetString("pooRecorder.homeassistantIp")
|
|
homeAssistantPort := viper.GetString("pooRecorder.homeassistantPort")
|
|
url := fmt.Sprintf("http://%s:%s/api/states/%s", homeAssistantIp, homeAssistantPort, pooStatus.EntityId)
|
|
payload, err := json.Marshal(pooStatus)
|
|
if err != nil {
|
|
slog.Warn(fmt.Sprintln("HandleRecordPoo Error marshalling poo status", err))
|
|
return
|
|
}
|
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(payload))
|
|
if err != nil {
|
|
slog.Warn(fmt.Sprintln("HandleRecordPoo Error creating request", err))
|
|
return
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+viper.GetString("pooRecorder.homeassistantToken"))
|
|
client := &http.Client{
|
|
Timeout: time.Second * 1,
|
|
}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
slog.Warn(fmt.Sprintln("HandleRecordPoo Error sending request", err))
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
slog.Warn(fmt.Sprintln("HandleRecordPoo Unexpected response status", resp.StatusCode))
|
|
}
|
|
defer resp.Body.Close()
|
|
} else {
|
|
slog.Warn("HandleRecordPoo Home Assistant IP, port, or token not found in config file")
|
|
}
|
|
}
|
|
|
|
func storeStatus(record recordDetail, timestamp time.Time) {
|
|
tableId := viper.GetString("pooRecorder.tableId")
|
|
recordDate := timestamp.Format("2006-01-02")
|
|
recordTime := timestamp.Format("15:04")
|
|
slog.Info(fmt.Sprintln("Recording poo", record.Status, "at", record.Latitude, record.Longitude))
|
|
go func() {
|
|
header, err := notion.GetTableRows(tableId, 1, "")
|
|
if err != nil {
|
|
slog.Warn(fmt.Sprintln("HandleRecordPoo Failed to get table header", err))
|
|
return
|
|
}
|
|
if len(header) == 0 {
|
|
slog.Warn("HandleRecordPoo Table header not found")
|
|
return
|
|
}
|
|
headerId := header[0].GetID()
|
|
err = notion.WriteTableRow([]string{recordDate, recordTime, record.Status, record.Latitude + "," + record.Longitude}, tableId, headerId.String())
|
|
if err != nil {
|
|
slog.Warn(fmt.Sprintln("HandleRecordPoo Failed to write table row", err))
|
|
}
|
|
}()
|
|
|
|
}
|
|
|
|
func migrateDb() {
|
|
|
|
}
|
|
|
|
func initDb() {
|
|
if !viper.InConfig("pooRecorder.dbPath") {
|
|
slog.Info("HandleRecordPoo dbPath not found in config file, using default: pooRecorder.db")
|
|
viper.SetDefault("pooRecorder.dbPath", "pooRecorder.db")
|
|
}
|
|
|
|
dbPath := viper.GetString("pooRecorder.dbPath")
|
|
err := error(nil)
|
|
db, err = sql.Open("sqlite3", dbPath)
|
|
if err != nil {
|
|
slog.Error(fmt.Sprintln("PooRecorderInit Error opening database", err))
|
|
os.Exit(1)
|
|
}
|
|
err = db.Ping()
|
|
if err != nil {
|
|
slog.Error(fmt.Sprintln("PooRecorderInit Error pinging database", err))
|
|
os.Exit(1)
|
|
}
|
|
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS poo_records (
|
|
timestamp TEXT PRIMARY KEY,
|
|
status TEXT,
|
|
latitude TEXT,
|
|
longitude TEXT)`)
|
|
|
|
}
|
|
|
|
func Init() {
|
|
initDb()
|
|
}
|
|
|
|
func HandleRecordPoo(w http.ResponseWriter, r *http.Request) {
|
|
var record recordDetail
|
|
if !viper.InConfig("pooRecorder.tableId") {
|
|
slog.Warn("HandleRecordPoo Table ID not found in config file")
|
|
http.Error(w, "Table ID not found in config file", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
decorder := json.NewDecoder(r.Body)
|
|
decorder.DisallowUnknownFields()
|
|
err := decorder.Decode(&record)
|
|
if err != nil {
|
|
slog.Warn(fmt.Sprintln("HandleRecordPoo Error decoding request body", err))
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
now := time.Now()
|
|
storeStatus(record, now)
|
|
timeAttribute := now.Format("Mon | 2006-01-02 | 15:04")
|
|
pooStatus := pooStatusHttpSensor{
|
|
EntityId: "sensor.test_poo_sensor",
|
|
State: record.Status,
|
|
Attributes: pooStatusHttpSensorAttributes{
|
|
LastPoo: timeAttribute,
|
|
},
|
|
}
|
|
publishPooStatus(pooStatus)
|
|
}
|