#include <WiFi.h>
#include <AsyncMqttClient.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>
#include <TokenIterator.h>
#include <UrlTokenBindings.h>
#include <NTPClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
/*
* Hostname
*/
String hostname = "Lamp1";
/*
* WiFi
*/
#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
/*
* MQTT Brocker
*/
#define MQTT_HOST "YOUR_MQTT_BROCKER_DOMAIN"
#define MQTT_PORT 1883
/*
* AsyncWebServer
*/
AsyncWebServer server(80);
/*
* Time
*/
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "time.nask.pl", 3600, 60000);
/*
* Temperature
*/
const int oneWireBus = 4;
OneWire oneWire(oneWireBus);
DallasTemperature sensors(&oneWire);
/*
* Leds & PWM
*/
#define JACK_COUNT 8
#define PWM_FREQ 100
#define PWM_RESOLUTION 8
const int jackPins[JACK_COUNT] = { 27, 26, 25, 33, 16, 17, 18, 19 };
const int pwmChannels[JACK_COUNT] = { 0, 1, 2, 3, 4, 5, 6, 7 };
#define ANALOG_INPUT_COUNT 0
int led_power[101];
int ch1State = 0;
int ch2State = 0;
int ch3State = 0;
int ch4State = 0;
int ch5State = 0;
int ch6State = 0;
int fan1State = 0;
int fan2State = 0;
/*
* MQTT
*/
AsyncMqttClient mqttClient;
TimerHandle_t mqttReconnectTimer;
TimerHandle_t wifiReconnectTimer;
void connectToMqtt() {
Serial.println("Connecting to MQTT...");
mqttClient.connect();
}
void onMqttConnect(bool sessionPresent) {
Serial.println("Connected to MQTT.");
Serial.print("Session present: ");
Serial.println(sessionPresent);
uint16_t packetIdSub1 = mqttClient.subscribe("reef-pi/l1_ch1", 1);
uint16_t packetIdSub2 = mqttClient.subscribe("reef-pi/l1_ch2", 1);
uint16_t packetIdSub3 = mqttClient.subscribe("reef-pi/l1_ch3", 1);
uint16_t packetIdSub4 = mqttClient.subscribe("reef-pi/l1_ch4", 1);
uint16_t packetIdSub5 = mqttClient.subscribe("reef-pi/l1_ch5", 1);
uint16_t packetIdSub6 = mqttClient.subscribe("reef-pi/l1_ch6", 1);
uint16_t packetIdSub7 = mqttClient.subscribe("reef-pi/l1_fan1", 1);
uint16_t packetIdSub8 = mqttClient.subscribe("reef-pi/l1_fan2", 1);
}
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
if (WiFi.isConnected()) {
xTimerStart(mqttReconnectTimer, 0);
}
}
void onMqttSubscribe(uint16_t packetId, uint8_t qos) {
Serial.println("Subscribe acknowledged.");
}
void onMqttUnsubscribe(uint16_t packetId) {
Serial.println("Unsubscribe acknowledged.");
}
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
if (String(topic) == "reef-pi/l1_ch1") {
const int value = atoi(payload);
if (value >= 0 && value < (sizeof(led_power) / sizeof(int))) {
ch1State = led_power[value];
ledcWrite(0, ch1State);
}
}
if (String(topic) == "reef-pi/l1_ch2") {
const int value = atoi(payload);
if (value >= 0 && value < (sizeof(led_power) / sizeof(int))) {
ch2State = led_power[value];
ledcWrite(1, ch2State);
}
}
if (String(topic) == "reef-pi/l1_ch3") {
const int value = atoi(payload);
if (value >= 0 && value < (sizeof(led_power) / sizeof(int))) {
ch3State = led_power[value];
ledcWrite(2, ch3State);
}
}
if (String(topic) == "reef-pi/l1_ch4") {
const int value = atoi(payload);
if (value >= 0 && value < (sizeof(led_power) / sizeof(int))) {
ch4State = led_power[value];
ledcWrite(3, ch4State);
}
}
if (String(topic) == "reef-pi/l1_ch5") {
const int value = atoi(payload);
if (value >= 0 && value < (sizeof(led_power) / sizeof(int))) {
ch5State = led_power[value];
ledcWrite(4, ch5State);
}
}
if (String(topic) == "reef-pi/l1_ch6") {
const int value = atoi(payload);
if (value >= 0 && value < (sizeof(led_power) / sizeof(int))) {
ch6State = led_power[value];
ledcWrite(5, ch6State);
}
}
if (String(topic) == "reef-pi/l1_fan1") {
const int value = atoi(payload);
if (value >= 0 && value < (sizeof(led_power) / sizeof(int))) {
fan1State = led_power[value];
ledcWrite(6, fan1State);
}
}
if (String(topic) == "reef-pi/l1_fan2") {
const int value = atoi(payload);
if (value >= 0 && value < (sizeof(led_power) / sizeof(int))) {
fan2State = led_power[value];
ledcWrite(7, fan2State);
}
}
}
void onMqttPublish(uint16_t packetId) {
}
/*
* WiFi Connection & Events
*/
void connectToWifi() {
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
WiFi.setHostname(hostname.c_str()); //define hostname
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
Serial.println("Connecting to WiFi..");
}
}
void WiFiEvent(WiFiEvent_t event) {
switch(event) {
case SYSTEM_EVENT_STA_GOT_IP:
delay(5000);
connectToMqtt();
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
xTimerStart(wifiReconnectTimer, 0);
break;
}
}
/*
* Setup
*/
void setup(void) {
Serial.begin(115200);
mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(5000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
wifiReconnectTimer = xTimerCreate("wifiTimer", pdMS_TO_TICKS(5000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToWifi));
WiFi.onEvent(WiFiEvent);
// MQTT
mqttClient.onConnect(onMqttConnect);
mqttClient.onDisconnect(onMqttDisconnect);
mqttClient.onSubscribe(onMqttSubscribe);
mqttClient.onUnsubscribe(onMqttUnsubscribe);
mqttClient.onMessage(onMqttMessage);
mqttClient.onPublish(onMqttPublish);
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
mqttClient.setCredentials("mqtt_user", "mqtt_password");
connectToWifi();
server.on("/analog_inputs/*", HTTP_GET, readAnalogInput);
server.on("/restart", HTTP_GET, [] (AsyncWebServerRequest *request) {
ESP.restart();
});
sensors.begin();
for (int i = 0; i < JACK_COUNT; i++) {
ledcSetup(pwmChannels[i], PWM_FREQ, PWM_RESOLUTION);
ledcAttachPin(jackPins[i], pwmChannels[i]);
}
timeClient.begin();
timeClient.setTimeOffset(2 * 3600); // add 3600s to NTP time
while (!timeClient.update()) {
timeClient.forceUpdate();
}
AsyncElegantOTA.begin(&server);
for (int j = 0; j < 101; j++) {
led_power[j] = map(j, 0, 100, 0, 255);
Serial.println(led_power[j]);
}
server.begin();
}
/*
* Loop
*/
void loop(void) {
}
UrlTokenBindings parseURL(AsyncWebServerRequest *request, char templatePath[]) {
char urlBuffer[30];
request->url().toCharArray(urlBuffer, 30);
int urlLength = request->url().length();
TokenIterator templateIterator(templatePath, strlen(templatePath), '/');
TokenIterator pathIterator(urlBuffer, urlLength, '/');
UrlTokenBindings bindings(templateIterator, pathIterator);
return bindings;
}
void readAnalogInput(AsyncWebServerRequest *request) {
char path[] = "/analog_inputs/:id";
UrlTokenBindings bindings = parseURL(request, path);
int id = String(bindings.get("id")).toInt();
if (id < 0 || id > ANALOG_INPUT_COUNT) {
request->send(409, "text/plain", "invalid analog input pin id");
return;
}
float value;
if (id == 0) {
sensors.requestTemperatures();
value = sensors.getTempCByIndex(0);
}
Serial.print("Temperature: ");
Serial.print(value);
Serial.println(" °C");
request->send(200, "text/plain", String(value));
}