diff --git a/BRUH Multisensor V1.123dx b/BRUH Multisensor V1.123dx new file mode 100644 index 0000000..88a1523 Binary files /dev/null and b/BRUH Multisensor V1.123dx differ diff --git a/BRUH Multisensor V1.stl b/BRUH Multisensor V1.stl new file mode 100644 index 0000000..dbb988d Binary files /dev/null and b/BRUH Multisensor V1.stl differ diff --git a/Sensor Node GitHub_bb.png b/Sensor Node GitHub_bb.png new file mode 100644 index 0000000..f3bec2b Binary files /dev/null and b/Sensor Node GitHub_bb.png differ diff --git a/bruh_mqtt_multisensor_github/bruh_mqtt_multisensor_github.ino b/bruh_mqtt_multisensor_github/bruh_mqtt_multisensor_github.ino new file mode 100644 index 0000000..e775235 --- /dev/null +++ b/bruh_mqtt_multisensor_github/bruh_mqtt_multisensor_github.ino @@ -0,0 +1,580 @@ +/* + .______ .______ __ __ __ __ ___ __ __ .___________. ______ .___ ___. ___ .___________. __ ______ .__ __. + | _ \ | _ \ | | | | | | | | / \ | | | | | | / __ \ | \/ | / \ | || | / __ \ | \ | | + | |_) | | |_) | | | | | | |__| | / ^ \ | | | | `---| |----`| | | | | \ / | / ^ \ `---| |----`| | | | | | | \| | + | _ < | / | | | | | __ | / /_\ \ | | | | | | | | | | | |\/| | / /_\ \ | | | | | | | | | . ` | + | |_) | | |\ \-.| `--' | | | | | / _____ \ | `--' | | | | `--' | | | | | / _____ \ | | | | | `--' | | |\ | + |______/ | _| `.__| \______/ |__| |__| /__/ \__\ \______/ |__| \______/ |__| |__| /__/ \__\ |__| |__| \______/ |__| \__| + + Thanks much to @corbanmailloux for providing a great framework for implementing flash/fade with HomeAssistant https://github.com/corbanmailloux/esp-mqtt-rgb-led +*/ + + + +#include +#include +#include +#include +#include +#include +#include + + + +/************ WIFI and MQTT INFORMATION (CHANGE THESE FOR YOUR SETUP) ******************/ +#define wifi_ssid "YourSSID" //type your WIFI information inside the quotes +#define wifi_password "YourWIFIpassword" +#define mqtt_server "your.mqtt.server.ip" +#define mqtt_user "yourMQTTusername" +#define mqtt_password "yourMQTTpassword" +#define mqtt_port 1883 + + +/************* MQTT TOPICS (change these topics as you wish) **************************/ +#define light_state_topic "bruh/sensornode1" +#define light_set_topic "bruh/sensornode1/set" + +const char* on_cmd = "ON"; +const char* off_cmd = "OFF"; + + + +/**************************** FOR OTA **************************************************/ +#define SENSORNAME "sensornode1" +#define OTApassword "bruh" +int OTAport = 8266; + + + +/**************************** PIN DEFINITIONS ********************************************/ +const int redPin = D1; +const int greenPin = D2; +const int bluePin = D3; +#define PIRPIN D5 +#define DHTPIN D7 +#define DHTTYPE DHT22 +#define LDRPIN A0 + + + +/**************************** SENSOR DEFINITIONS *******************************************/ +float ldrValue; +int LDR; +float calcLDR; +float diffLDR = 25; + +float diffTEMP = 0.2; +float tempValue; + +float diffHUM = 1; +float humValue; + +int pirValue; +int pirStatus; +String motionStatus; + +char message_buff[100]; + +int calibrationTime = 0; + +const int BUFFER_SIZE = 300; + + + +/******************************** GLOBALS for fade/flash *******************************/ +byte red = 255; +byte green = 255; +byte blue = 255; +byte brightness = 255; + +byte realRed = 0; +byte realGreen = 0; +byte realBlue = 0; + +bool stateOn = false; + +bool startFade = false; +unsigned long lastLoop = 0; +int transitionTime = 0; +bool inFade = false; +int loopCount = 0; +int stepR, stepG, stepB; +int redVal, grnVal, bluVal; + +bool flash = false; +bool startFlash = false; +int flashLength = 0; +unsigned long flashStartTime = 0; +byte flashRed = red; +byte flashGreen = green; +byte flashBlue = blue; +byte flashBrightness = brightness; + + + +WiFiClient espClient; +PubSubClient client(espClient); +DHT dht(DHTPIN, DHTTYPE); + + + +/********************************** START SETUP*****************************************/ +void setup() { + + Serial.begin(115200); + + pinMode(PIRPIN, INPUT); + pinMode(DHTPIN, INPUT); + pinMode(LDRPIN, INPUT); + + Serial.begin(115200); + delay(10); + + ArduinoOTA.setPort(OTAport); + + ArduinoOTA.setHostname(SENSORNAME); + + ArduinoOTA.setPassword((const char *)OTApassword); + + Serial.print("calibrating sensor "); + for (int i = 0; i < calibrationTime; i++) { + Serial.print("."); + delay(1000); + } + + Serial.println("Starting Node named " + String(SENSORNAME)); + + + setup_wifi(); + + client.setServer(mqtt_server, mqtt_port); + client.setCallback(callback); + + + ArduinoOTA.onStart([]() { + Serial.println("Starting"); + }); + ArduinoOTA.onEnd([]() { + Serial.println("\nEnd"); + }); + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { + Serial.printf("Progress: %u%%\r", (progress / (total / 100))); + }); + ArduinoOTA.onError([](ota_error_t error) { + Serial.printf("Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); + else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); + else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); + else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); + else if (error == OTA_END_ERROR) Serial.println("End Failed"); + }); + ArduinoOTA.begin(); + Serial.println("Ready"); + Serial.print("IPess: "); + Serial.println(WiFi.localIP()); + +} + + + + +/********************************** START SETUP WIFI*****************************************/ +void setup_wifi() { + + delay(10); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(wifi_ssid); + + WiFi.mode(WIFI_STA); + WiFi.begin(wifi_ssid, wifi_password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); +} + + + +/********************************** START CALLBACK*****************************************/ +void callback(char* topic, byte* payload, unsigned int length) { + Serial.print("Message arrived ["); + Serial.print(topic); + Serial.print("] "); + + char message[length + 1]; + for (int i = 0; i < length; i++) { + message[i] = (char)payload[i]; + } + message[length] = '\0'; + Serial.println(message); + + if (!processJson(message)) { + return; + } + + if (stateOn) { + // Update lights + realRed = map(red, 0, 255, 0, brightness); + realGreen = map(green, 0, 255, 0, brightness); + realBlue = map(blue, 0, 255, 0, brightness); + } + else { + realRed = 0; + realGreen = 0; + realBlue = 0; + } + + startFade = true; + inFade = false; // Kill the current fade + + sendState(); +} + + + +/********************************** START PROCESS JSON*****************************************/ +bool processJson(char* message) { + StaticJsonBuffer jsonBuffer; + + JsonObject& root = jsonBuffer.parseObject(message); + + if (!root.success()) { + Serial.println("parseObject() failed"); + return false; + } + + if (root.containsKey("state")) { + if (strcmp(root["state"], on_cmd) == 0) { + stateOn = true; + } + else if (strcmp(root["state"], off_cmd) == 0) { + stateOn = false; + } + } + + // If "flash" is included, treat RGB and brightness differently + if (root.containsKey("flash")) { + flashLength = (int)root["flash"] * 1000; + + if (root.containsKey("brightness")) { + flashBrightness = root["brightness"]; + } + else { + flashBrightness = brightness; + } + + if (root.containsKey("color")) { + flashRed = root["color"]["r"]; + flashGreen = root["color"]["g"]; + flashBlue = root["color"]["b"]; + } + else { + flashRed = red; + flashGreen = green; + flashBlue = blue; + } + + flashRed = map(flashRed, 0, 255, 0, flashBrightness); + flashGreen = map(flashGreen, 0, 255, 0, flashBrightness); + flashBlue = map(flashBlue, 0, 255, 0, flashBrightness); + + flash = true; + startFlash = true; + } + else { // Not flashing + flash = false; + + if (root.containsKey("color")) { + red = root["color"]["r"]; + green = root["color"]["g"]; + blue = root["color"]["b"]; + } + + if (root.containsKey("brightness")) { + brightness = root["brightness"]; + } + + if (root.containsKey("transition")) { + transitionTime = root["transition"]; + } + else { + transitionTime = 0; + } + } + + return true; +} + + + +/********************************** START SEND STATE*****************************************/ +void sendState() { + StaticJsonBuffer jsonBuffer; + + JsonObject& root = jsonBuffer.createObject(); + + root["state"] = (stateOn) ? on_cmd : off_cmd; + JsonObject& color = root.createNestedObject("color"); + color["r"] = red; + color["g"] = green; + color["b"] = blue; + + + root["brightness"] = brightness; + root["humidity"] = (String)humValue; + root["motion"] = (String)motionStatus; + root["ldr"] = (String)LDR; + root["temperature"] = (String)tempValue; + + + char buffer[root.measureLength() + 1]; + root.printTo(buffer, sizeof(buffer)); + + Serial.println(buffer); + client.publish(light_state_topic, buffer, true); +} + + +/********************************** START SET COLOR *****************************************/ +void setColor(int inR, int inG, int inB) { + analogWrite(redPin, inR); + analogWrite(greenPin, inG); + analogWrite(bluePin, inB); + + Serial.println("Setting LEDs:"); + Serial.print("r: "); + Serial.print(inR); + Serial.print(", g: "); + Serial.print(inG); + Serial.print(", b: "); + Serial.println(inB); +} + + + +/********************************** START RECONNECT*****************************************/ +void reconnect() { + // Loop until we're reconnected + while (!client.connected()) { + Serial.print("Attempting MQTT connection..."); + // Attempt to connect + if (client.connect(SENSORNAME, mqtt_user, mqtt_password)) { + Serial.println("connected"); + client.subscribe(light_set_topic); + setColor(0, 0, 0); + sendState(); + } else { + Serial.print("failed, rc="); + Serial.print(client.state()); + Serial.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } +} + + + +/********************************** START CHECK SENSOR **********************************/ +bool checkBoundSensor(float newValue, float prevValue, float maxDiff) { + return newValue < prevValue - maxDiff || newValue > prevValue + maxDiff; +} + + + +/********************************** START MAIN LOOP***************************************/ +void loop() { + + ArduinoOTA.handle(); + + if (!client.connected()) { + reconnect(); + } + client.loop(); + + + if (!inFade) { + + float newTempValue = dht.readTemperature(true); + float newHumValue = dht.readHumidity(); + + //PIR CODE + pirValue = digitalRead(PIRPIN); //read state of the + + if (pirValue == LOW && pirStatus != 1) { + motionStatus = "standby"; + sendState(); + pirStatus = 1; + } + + else if (pirValue == HIGH && pirStatus != 2) { + motionStatus = "motion detected"; + sendState(); + pirStatus = 2; + } + + delay(100); + + if (checkBoundSensor(newTempValue, tempValue, diffTEMP)) { + tempValue = newTempValue; + sendState(); + } + + if (checkBoundSensor(newHumValue, humValue, diffHUM)) { + humValue = newHumValue; + sendState(); + } + + + int newLDR = analogRead(LDRPIN); + + if (checkBoundSensor(newLDR, LDR, diffLDR)) { + LDR = newLDR; + sendState(); + } + + } + + if (flash) { + if (startFlash) { + startFlash = false; + flashStartTime = millis(); + } + + if ((millis() - flashStartTime) <= flashLength) { + if ((millis() - flashStartTime) % 1000 <= 500) { + setColor(flashRed, flashGreen, flashBlue); + } + else { + setColor(0, 0, 0); + // If you'd prefer the flashing to happen "on top of" + // the current color, uncomment the next line. + // setColor(realRed, realGreen, realBlue); + } + } + else { + flash = false; + setColor(realRed, realGreen, realBlue); + } + } + + if (startFade) { + // If we don't want to fade, skip it. + if (transitionTime == 0) { + setColor(realRed, realGreen, realBlue); + + redVal = realRed; + grnVal = realGreen; + bluVal = realBlue; + + startFade = false; + } + else { + loopCount = 0; + stepR = calculateStep(redVal, realRed); + stepG = calculateStep(grnVal, realGreen); + stepB = calculateStep(bluVal, realBlue); + + inFade = true; + } + } + + if (inFade) { + startFade = false; + unsigned long now = millis(); + if (now - lastLoop > transitionTime) { + if (loopCount <= 1020) { + lastLoop = now; + + redVal = calculateVal(stepR, redVal, loopCount); + grnVal = calculateVal(stepG, grnVal, loopCount); + bluVal = calculateVal(stepB, bluVal, loopCount); + + setColor(redVal, grnVal, bluVal); // Write current values to LED pins + + Serial.print("Loop count: "); + Serial.println(loopCount); + loopCount++; + } + else { + inFade = false; + } + } + } +} + + + + +/**************************** START TRANSITION FADER *****************************************/ +// From https://www.arduino.cc/en/Tutorial/ColorCrossfader +/* BELOW THIS LINE IS THE MATH -- YOU SHOULDN'T NEED TO CHANGE THIS FOR THE BASICS + + The program works like this: + Imagine a crossfade that moves the red LED from 0-10, + the green from 0-5, and the blue from 10 to 7, in + ten steps. + We'd want to count the 10 steps and increase or + decrease color values in evenly stepped increments. + Imagine a + indicates raising a value by 1, and a - + equals lowering it. Our 10 step fade would look like: + + 1 2 3 4 5 6 7 8 9 10 + R + + + + + + + + + + + G + + + + + + B - - - + + The red rises from 0 to 10 in ten steps, the green from + 0-5 in 5 steps, and the blue falls from 10 to 7 in three steps. + + In the real program, the color percentages are converted to + 0-255 values, and there are 1020 steps (255*4). + + To figure out how big a step there should be between one up- or + down-tick of one of the LED values, we call calculateStep(), + which calculates the absolute gap between the start and end values, + and then divides that gap by 1020 to determine the size of the step + between adjustments in the value. +*/ +int calculateStep(int prevValue, int endValue) { + int step = endValue - prevValue; // What's the overall gap? + if (step) { // If its non-zero, + step = 1020 / step; // divide by 1020 + } + + return step; +} + +/* The next function is calculateVal. When the loop value, i, + reaches the step size appropriate for one of the + colors, it increases or decreases the value of that color by 1. + (R, G, and B are each calculated separately.) +*/ +int calculateVal(int step, int val, int i) { + if ((step) && i % step == 0) { // If step is non-zero and its time to change a value, + if (step > 0) { // increment the value if step is positive... + val += 1; + } + else if (step < 0) { // ...or decrement it if step is negative + val -= 1; + } + } + + // Defensive driving: make sure val stays in the range 0-255 + if (val > 255) { + val = 255; + } + else if (val < 0) { + val = 0; + } + + return val; +} + diff --git a/mqtt_multisensor_sample_home_assistant_configuration.yaml b/mqtt_multisensor_sample_home_assistant_configuration.yaml new file mode 100644 index 0000000..9b4ef9e --- /dev/null +++ b/mqtt_multisensor_sample_home_assistant_configuration.yaml @@ -0,0 +1,54 @@ +mqtt: + broker: your.mqtt.ip.address + port: 1883 + client_id: home-assistant-1 + username: YOURUSERNAME + password: YOURPASSWORD + + +light: + - platform: mqtt_json + name: "SN1 LED" + state_topic: "bruh/sensornode1" + command_topic: "bruh/sensornode1/set" + brightness: true + flash: true + rgb: true + optimistic: false + qos: 0 + + +sensor: + - platform: mqtt + state_topic: "bruh/sensornode1" + name: "SN1 Humidity" + unit_of_measurement: "%" + value_template: '{{ value_json.humidity | round(1) }}' + + - platform: mqtt + state_topic: "bruh/sensornode1" + name: "SN1 LDR" + unit_of_measurement: "LUX" + value_template: '{{ value_json.ldr }}' + + - platform: mqtt + state_topic: "bruh/sensornode1" + name: "SN1 PIR" + value_template: '{{ value_json.motion }}' + + - platform: mqtt + state_topic: "bruh/sensornode1" + name: "SN1 Temperature" + unit_of_measurement: "°F" + value_template: '{{ value_json.temperature | round(1) }}' + + +group: + sensor_node_1_card: + name: Sensor Node 1 + entities: + - sensor.sn1_temperature + - sensor.sn1_humidity + - sensor.sn1_ldr + - sensor.sn1_pir + - light.sn1_led \ No newline at end of file