Skip to content

Instantly share code, notes, and snippets.

@sstallion
Last active February 1, 2024 04:08
Show Gist options
  • Save sstallion/4c263769306c5fc2fb87d65e11a809d9 to your computer and use it in GitHub Desktop.
Save sstallion/4c263769306c5fc2fb87d65e11a809d9 to your computer and use it in GitHub Desktop.
Arduino Sketch for an Aquarium Light in Home Assistant
#include <Arduino.h>
#include <SPI.h>
#include <WiFiNINA.h>
#include <ArduinoHA.h>
namespace {
constexpr auto WIFI_SSID = "<SSID>";
constexpr auto WIFI_PASS = "<PASSWORD>";
constexpr auto MQTT_BROKER = "<HOSTNAME>";
constexpr auto MQTT_USER = "<USERNAME>";
constexpr auto MQTT_PASS = "<PASSWORD>";
constexpr auto BUTTON_PIN = 2;
constexpr auto RED_PIN = 10;
constexpr auto GREEN_PIN = 11;
constexpr auto BLUE_PIN = 9;
WiFiClient client;
HADevice device;
HAMqtt mqtt{client, device};
HALight light{ "light", HALight::RGBFeature };
// Interrupts are used to handle button input rather than polling due to
// network-related delays, which can result in missed button presses. The
// following flag is used to indicate when loop() should publish a state
// change triggered by a button press:
volatile bool publishCurrentState;
void printHex(byte value) {
if (value < 0xF) {
Serial.print("0");
}
Serial.print(value, HEX);
}
void printMACAddress(byte mac[]) {
for (auto i = WL_MAC_ADDR_LENGTH - 1; i >= 0; i--) {
printHex(mac[i]);
if (i > 0) {
Serial.print(":");
}
}
}
void writeRGB(byte red, byte green, byte blue) {
analogWrite(RED_PIN, red);
analogWrite(GREEN_PIN, green);
analogWrite(BLUE_PIN, blue);
}
void setCurrentState(bool state) {
if (state) {
auto& color = light.getCurrentRGBColor();
writeRGB(color.red, color.green, color.blue);
} else {
writeRGB(0, 0, 0);
}
light.setCurrentState(state);
}
void toggleCurrentState() {
static unsigned long last; // debounce input
if (auto t = millis() - last; t > 250) {
setCurrentState(!light.getCurrentState());
publishCurrentState = true;
last = millis();
}
}
void onStateCommand(bool state, HALight* /*sender*/) {
Serial.print("Received state command: ");
Serial.println(state ? "on" : "off");
setCurrentState(state);
}
void onRGBColorCommand(HALight::RGBColor color, HALight* /*sender*/) {
Serial.print("Received RGB color command: #");
printHex(color.red);
printHex(color.green);
printHex(color.blue);
Serial.println();
light.setCurrentRGBColor(color);
}
} // namespace
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);
Serial.begin(9600);
byte mac[WL_MAC_ADDR_LENGTH];
WiFi.macAddress(mac);
Serial.print("MAC Address: ");
printMACAddress(mac);
Serial.println();
device.setUniqueId(mac, sizeof(mac));
device.setName("Fish Tank");
device.setManufacturer("<MFR>");
device.setModel("<MODEL>");
device.enableSharedAvailability();
device.enableLastWill();
light.setName("Fish Tank");
light.setIcon("mdi:fish");
light.setOptimistic(true);
light.onStateCommand(onStateCommand);
light.onRGBColorCommand(onRGBColorCommand);
auto defaultRGBColor = HALight::RGBColor{ 255, 255, 255 };
light.setCurrentRGBColor(defaultRGBColor);
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), toggleCurrentState, FALLING);
byte status;
do {
Serial.print("Connecting to SSID: ");
Serial.println(WIFI_SSID);
status = WiFi.begin(WIFI_SSID, WIFI_PASS);
} while (status != WL_CONNECTED);
Serial.print("Signal Strength (dBm): ");
Serial.println(WiFi.RSSI());
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
Serial.print("Netmask: ");
Serial.println(WiFi.subnetMask());
Serial.print("Gateway: ");
Serial.println(WiFi.gatewayIP());
Serial.print("Connecting to MQTT Broker: ");
Serial.println(MQTT_BROKER);
mqtt.begin(MQTT_BROKER, MQTT_USER, MQTT_PASS);
}
void loop() {
mqtt.loop();
if (publishCurrentState) {
noInterrupts();
auto state = light.getCurrentState();
publishCurrentState = false;
interrupts();
Serial.print("Publishing current state: ");
Serial.println(state ? "on" : "off");
light.setState(state, true); // force
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment