175 lines
4.8 KiB
C++
175 lines
4.8 KiB
C++
#include <Arduino_LED_Matrix.h>
|
|
#include <DallasTemperature.h>
|
|
#include <OneWire.h>
|
|
#include <WiFiS3.h>
|
|
|
|
#include "arduino_secrets.h"
|
|
|
|
constexpr uint8_t ROWS = 8;
|
|
constexpr uint8_t COLUMNS = 12;
|
|
constexpr uint8_t ONE_WIRE_PIN = 2;
|
|
constexpr unsigned long PAYLOAD_INTERVAL_MS = 10000;
|
|
constexpr unsigned long WIFI_RETRY_MS = 3000;
|
|
constexpr unsigned long RESPONSE_TIMEOUT_MS = 5000;
|
|
|
|
constexpr char API_HOST[] = "payloads.p20.dev";
|
|
constexpr uint16_t API_PORT = 443;
|
|
constexpr char API_PATH[] = "/api/payloads";
|
|
|
|
ArduinoLEDMatrix matrix;
|
|
OneWire oneWire(ONE_WIRE_PIN);
|
|
DallasTemperature temperatureSensors(&oneWire);
|
|
uint8_t frame[ROWS][COLUMNS] = {};
|
|
|
|
unsigned long lastPayloadAt = 0;
|
|
unsigned long lastWiFiAttemptAt = 0;
|
|
int lastDisplayedSeconds = -1;
|
|
bool lastDisplayedConnected = false;
|
|
|
|
void clearFrame() {
|
|
memset(frame, 0, sizeof(frame));
|
|
}
|
|
|
|
void setPixel(int x, int y, bool on = true) {
|
|
if (x >= 0 && x < COLUMNS && y >= 0 && y < ROWS) {
|
|
frame[y][x] = on ? 1 : 0;
|
|
}
|
|
}
|
|
|
|
void showCountdown(uint8_t secondsRemaining, bool connected) {
|
|
clearFrame();
|
|
|
|
// Wi-Fi status: a check mark when connected, an X otherwise.
|
|
if (connected) {
|
|
setPixel(0, 2);
|
|
setPixel(1, 3);
|
|
setPixel(2, 2);
|
|
setPixel(3, 1);
|
|
} else {
|
|
setPixel(0, 0);
|
|
setPixel(1, 1);
|
|
setPixel(2, 2);
|
|
setPixel(2, 0);
|
|
setPixel(0, 2);
|
|
}
|
|
|
|
// Ten LEDs count down from 10 to 1 before the next payload.
|
|
const uint8_t lit = min(secondsRemaining, static_cast<uint8_t>(10));
|
|
for (uint8_t column = 0; column < lit; ++column) {
|
|
setPixel(column + 1, 6);
|
|
}
|
|
matrix.renderBitmap(frame, ROWS, COLUMNS);
|
|
}
|
|
|
|
void connectWiFi() {
|
|
if (WiFi.status() == WL_CONNECTED) return;
|
|
if (millis() - lastWiFiAttemptAt < WIFI_RETRY_MS) return;
|
|
|
|
lastWiFiAttemptAt = millis();
|
|
Serial.print(F("Forbinder til Wi-Fi: "));
|
|
Serial.println(SECRET_SSID);
|
|
WiFi.begin(SECRET_SSID, SECRET_PASS);
|
|
}
|
|
|
|
bool postTemperature(float celsius) {
|
|
WiFiSSLClient client;
|
|
if (!client.connect(API_HOST, API_PORT)) {
|
|
Serial.println(F("Kunne ikke oprette HTTPS-forbindelse til payload-serveren."));
|
|
return false;
|
|
}
|
|
|
|
String body = F("{\"topic\":\"sensors/temperature\",\"payload\":{");
|
|
body += F("\"device\":\"uno-r4-wifi-ds18b20\",\"temperatureC\":");
|
|
body += String(celsius, 2);
|
|
body += F("}}");
|
|
|
|
client.print(F("POST "));
|
|
client.print(API_PATH);
|
|
client.println(F(" HTTP/1.1"));
|
|
client.print(F("Host: "));
|
|
client.println(API_HOST);
|
|
client.print(F("Authorization: Bearer "));
|
|
client.println(SECRET_API_TOKEN);
|
|
client.println(F("Content-Type: application/json"));
|
|
client.println(F("X-Device-ID: uno-r4-wifi-ds18b20"));
|
|
client.println(F("X-Client-Name: ds18b20-payload-sketch"));
|
|
client.print(F("Content-Length: "));
|
|
client.println(body.length());
|
|
client.println(F("Connection: close"));
|
|
client.println();
|
|
client.print(body);
|
|
|
|
const unsigned long startedAt = millis();
|
|
while (!client.available() && client.connected() &&
|
|
millis() - startedAt < RESPONSE_TIMEOUT_MS) {
|
|
delay(10);
|
|
}
|
|
|
|
if (!client.available()) {
|
|
Serial.println(F("Payload-serveren svarede ikke inden timeout."));
|
|
client.stop();
|
|
return false;
|
|
}
|
|
|
|
const String statusLine = client.readStringUntil('\n');
|
|
const bool accepted = statusLine.indexOf(" 201 ") >= 0;
|
|
Serial.print(F("Serverens svar: "));
|
|
Serial.println(statusLine);
|
|
client.stop();
|
|
return accepted;
|
|
}
|
|
|
|
void sendPayload() {
|
|
temperatureSensors.requestTemperatures();
|
|
const float celsius = temperatureSensors.getTempCByIndex(0);
|
|
|
|
if (celsius == DEVICE_DISCONNECTED_C) {
|
|
Serial.println(F("DS18B20 blev ikke fundet paa 1-Wire-bussen."));
|
|
return;
|
|
}
|
|
|
|
Serial.print(F("Temperatur: "));
|
|
Serial.print(celsius, 2);
|
|
Serial.println(F(" C"));
|
|
Serial.println(postTemperature(celsius) ? F("Payload sendt.") : F("Payload fejlede."));
|
|
}
|
|
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
matrix.begin();
|
|
temperatureSensors.begin();
|
|
temperatureSensors.setResolution(10);
|
|
|
|
showCountdown(10, false);
|
|
lastWiFiAttemptAt = millis() - WIFI_RETRY_MS;
|
|
connectWiFi();
|
|
lastPayloadAt = millis();
|
|
}
|
|
|
|
void loop() {
|
|
connectWiFi();
|
|
|
|
const unsigned long elapsed = millis() - lastPayloadAt;
|
|
const uint8_t secondsRemaining = elapsed >= PAYLOAD_INTERVAL_MS
|
|
? 0
|
|
: static_cast<uint8_t>((PAYLOAD_INTERVAL_MS - elapsed + 999) / 1000);
|
|
|
|
const bool connected = WiFi.status() == WL_CONNECTED;
|
|
if (secondsRemaining != lastDisplayedSeconds || connected != lastDisplayedConnected) {
|
|
lastDisplayedSeconds = secondsRemaining;
|
|
lastDisplayedConnected = connected;
|
|
showCountdown(secondsRemaining, connected);
|
|
}
|
|
|
|
if (elapsed >= PAYLOAD_INTERVAL_MS) {
|
|
if (WiFi.status() == WL_CONNECTED) {
|
|
sendPayload();
|
|
} else {
|
|
Serial.println(F("Payload sprunget over: Wi-Fi er ikke forbundet."));
|
|
}
|
|
lastPayloadAt = millis();
|
|
lastDisplayedSeconds = -1;
|
|
}
|
|
|
|
delay(20);
|
|
}
|