diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..fd99231 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,29 @@ +name: Release docker image with latest proxy server + +on: + release: + types: + - released + tags: + - '*' + + +env: + TAG: ${{ github.event.release.tag_name }} + DOCKER_HUB_ID: ${{ secrets.DOCKER_HUB_ID }} + DOCKER_HUB_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }} + +jobs: + docker: + name: Publish docker image + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v2 + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ env.DOCKER_HUB_ID }} + password: ${{ env.DOCKER_HUB_PASSWORD }} + - run: make build + - run: make publish \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..485dee6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8a3396b --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +.PHONY: build +build: + @docker build --target server -t brushknight/terrarium-proxy:latest -f server/Dockerfile server + +.PHONY: publish +publish: + @docker push brushknight/terrarium-proxy:latest diff --git a/esp32/src/climate.cpp b/esp32/src/climate.cpp index 100947e..6d1f1fc 100644 --- a/esp32/src/climate.cpp +++ b/esp32/src/climate.cpp @@ -1,11 +1,8 @@ #include "climate.h" - namespace Climate { - - /* schedule 08 - 20 hot max 29.5 @@ -30,7 +27,7 @@ namespace Climate #define DHT_COLD_CENTER_PIN 5 // #3 #define DHT_COLD_SIDE_PIN 18 // #4 -#define DAY_MAX_TEMP 30//30 +#define DAY_MAX_TEMP 30 //30 #define DAY_TEMP_TOLERANCE 1 #define NIGHT_MAX_TEMP 24 #define NIGHT_TEMP_TOLERANCE 1 @@ -51,27 +48,27 @@ namespace Climate dht.temperature().getEvent(&event); if (isnan(event.temperature)) { - Serial.println(F("Error reading temperature!")); + // Serial.println(F("Error reading temperature!")); } else { data.t = event.temperature; - Serial.print(F("Temperature: ")); - Serial.print(event.temperature); - Serial.println(F("°C")); + // Serial.print(F("Temperature: ")); + // Serial.print(event.temperature); + // Serial.println(F("°C")); } // Get humidity event and print its value. dht.humidity().getEvent(&event); if (isnan(event.relative_humidity)) { - Serial.println(F("Error reading humidity!")); + // Serial.println(F("Error reading humidity!")); } else { data.h = event.relative_humidity; - Serial.print(F("Humidity: ")); - Serial.print(event.relative_humidity); - Serial.println(F("%")); + // Serial.print(F("Humidity: ")); + // Serial.print(event.relative_humidity); + // Serial.println(F("%")); } return data; } @@ -80,6 +77,7 @@ namespace Climate { relayState = HIGH; digitalWrite(HEATER_RELAY_PIN, relayState); + Serial.println("turn relay on"); } void turnRelayOff() @@ -97,7 +95,6 @@ namespace Climate dhtHotCenter.begin(); dhtColdCenter.begin(); dhtColdSide.begin(); - Serial.println("turn relay on"); } Telemetry::TelemteryData climateControl(int hour, int minute) @@ -105,13 +102,6 @@ namespace Climate bool isDay = hour >= DAY_START_HOUR && hour < NIGHT_START_HOUR && minute >= DAY_START_MINUTE; - // read all temps - - // if hot 1,2 temp is > limit - // turn heating off - // if hot 1,2 temp is < limit - tolerance - // turn heating on - Serial.print("is day: "); Serial.println(isDay); @@ -124,44 +114,67 @@ namespace Climate Serial.println("4: cold side"); ClimateData coldSide = readTempHumid(dhtColdSide); + Telemetry::TelemteryData telemetryData = Telemetry::TelemteryData(); + if (isDay) { if (hotSide.t < DAY_MAX_TEMP - DAY_TEMP_TOLERANCE && hotCenter.t < DAY_MAX_TEMP - DAY_TEMP_TOLERANCE) { turnRelayOn(); - }else{ + telemetryData.heater = true; + } + else + { turnRelayOff(); + telemetryData.heater = false; } // safety check if (hotSide.t > DAY_MAX_TEMP || hotCenter.t > DAY_MAX_TEMP) { turnRelayOff(); + telemetryData.heater = false; } } else { + // Serial.print("test night condition 1: "); + // Serial.println(hotSide.t < NIGHT_MAX_TEMP - NIGHT_TEMP_TOLERANCE); + + // Serial.print("test night condition 2: "); + // Serial.println(hotCenter.t < NIGHT_MAX_TEMP - NIGHT_TEMP_TOLERANCE); + if (hotSide.t < NIGHT_MAX_TEMP - NIGHT_TEMP_TOLERANCE && hotCenter.t < NIGHT_MAX_TEMP - NIGHT_TEMP_TOLERANCE) { turnRelayOn(); - }else{ + telemetryData.heater = true; + } + else + { turnRelayOff(); + telemetryData.heater = false; } // safety check if (hotSide.t > NIGHT_MAX_TEMP || hotCenter.t > NIGHT_MAX_TEMP) { turnRelayOff(); + telemetryData.heater = false; } } - Telemetry::TelemteryData telemetryData = Telemetry::TelemteryData(); telemetryData.hotSide = hotSide; telemetryData.hotCenter = hotCenter; telemetryData.coldCenter = coldCenter; telemetryData.coldSide = coldSide; + + telemetryData.climateConfig.dayMaxTemp = DAY_MAX_TEMP; + telemetryData.climateConfig.nightMaxTemp = NIGHT_MAX_TEMP; + telemetryData.climateConfig.dayTempTolerance = DAY_TEMP_TOLERANCE; + telemetryData.climateConfig.nightTempTolerance = NIGHT_TEMP_TOLERANCE; + return telemetryData; } } diff --git a/esp32/src/telemetry.cpp b/esp32/src/telemetry.cpp index 79d5a9b..89cea1c 100644 --- a/esp32/src/telemetry.cpp +++ b/esp32/src/telemetry.cpp @@ -16,7 +16,9 @@ namespace Telemetry http.begin(TELEMETRY_ENDPOINT); http.addHeader("Content-Type", "application/json"); - StaticJsonDocument<200> doc; + StaticJsonDocument<400> doc; + + doc["heater"] = telemteryData.heater; doc.createNestedObject("hot_side"); doc["hot_side"]["H"] = telemteryData.hotSide.h; @@ -37,9 +39,19 @@ namespace Telemetry doc["cold_side"]["H"] = telemteryData.coldSide.h; doc["cold_side"]["T"] = telemteryData.coldSide.t; + + doc.createNestedObject("climate_config"); + doc["climate_config"]["day_max_temp"] = telemteryData.climateConfig.dayMaxTemp; + doc["climate_config"]["night_max_temp"] = telemteryData.climateConfig.nightMaxTemp; + doc["climate_config"]["day_temp_tolerance"] = telemteryData.climateConfig.dayTempTolerance; + doc["climate_config"]["night_temp_tolerance"] = telemteryData.climateConfig.nightTempTolerance; + + String requestBody; serializeJson(doc, requestBody); + Serial.println(requestBody); + int httpResponseCode = http.POST(requestBody); if (httpResponseCode > 0) @@ -47,8 +59,8 @@ namespace Telemetry String response = http.getString(); - Serial.println(httpResponseCode); - Serial.println(response); + // Serial.println(httpResponseCode); + // Serial.println(response); } else { diff --git a/esp32/src/telemetry.h b/esp32/src/telemetry.h index 8a01b94..eae40b5 100644 --- a/esp32/src/telemetry.h +++ b/esp32/src/telemetry.h @@ -3,13 +3,20 @@ #include "climate_data.h" - namespace Telemetry { - using namespace Climate; + class ClimateConfig + { + public: + float dayMaxTemp; + float nightMaxTemp; + float dayTempTolerance; + float nightTempTolerance; + }; + class TelemteryData { public: @@ -17,6 +24,8 @@ namespace Telemetry ClimateData hotCenter; ClimateData coldCenter; ClimateData coldSide; + ClimateConfig climateConfig; + bool heater; }; void send(TelemteryData telemteryData); diff --git a/server/Dockerfile b/server/Dockerfile new file mode 100644 index 0000000..6194a08 --- /dev/null +++ b/server/Dockerfile @@ -0,0 +1,50 @@ +# Dockerfile References: https://docs.docker.com/engine/reference/builder/ + +### Build binary + +# Start from the latest golang base image +FROM golang:latest AS builder + +# Add Maintainer Info +LABEL maintainer="Grigorii Merkushev " + +# Set the Current Working Directory inside the container +WORKDIR /app + +# Copy go mod and sum files +COPY go.mod go.sum ./ + +# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed +RUN go mod download + +# Copy the source from the current directory to the Working Directory inside the container +COPY server.go . + +# Build the Go apps +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o server server.go + +### +### Create image with binary +### + +# Start from the latest alpine base image +FROM alpine:latest AS server + +# Set the Current Working Directory inside the container +WORKDIR /app + +# Copy zoneinfo +RUN apk --no-cache add tzdata + +# Copy artifacts created in previous step +COPY --from=builder /app/server . + +# Add executable permissions +RUN chmod +x ./server + +# Command to run the executable +ENTRYPOINT ["./server"] + +# Expose port 80 to the outside world +EXPOSE 80 + diff --git a/server/server.go b/server/server.go index e0b5734..b87afb7 100644 --- a/server/server.go +++ b/server/server.go @@ -16,11 +16,20 @@ type ClimateData struct { H float64 `json:"h"` } +type ClimateConfig struct { + DayMaxTemp float64 `json:"day_max_temp"` + NightMaxTemp float64 `json:"night_max_temp"` + DayTempTolerance float64 `json:"day_temp_tolerance"` + NightTempTolerance float64 `json:"night_temp_tolerance"` +} + type Data struct { - HotSide ClimateData `json:"hot_side"` - HotCenter ClimateData `json:"hot_center"` - ColdCenter ClimateData `json:"cold_center"` - ColdSide ClimateData `json:"cold_side"` + HotSide ClimateData `json:"hot_side"` + HotCenter ClimateData `json:"hot_center"` + ColdCenter ClimateData `json:"cold_center"` + ColdSide ClimateData `json:"cold_side"` + Heater bool `json:"heater"` + Config ClimateConfig `json:"climate_config"` } var errResponse struct {