Skip to content

Instantly share code, notes, and snippets.

@LucasPlacentino
Forked from mmarquez76/MotionWarn.ino
Last active July 16, 2023 16:53
Show Gist options
  • Save LucasPlacentino/1b34b044e0f859721b45c40ae0876e54 to your computer and use it in GitHub Desktop.
Save LucasPlacentino/1b34b044e0f859721b45c40ae0876e54 to your computer and use it in GitHub Desktop.
Flash WiZ-connected light bulbs when a motion sensor is tripped using Arduino
// for details about wiz local control, see:
// https://aleksandr.rogozin.us/blog/2021/8/13/hacking-philips-wiz-lights-via-command-line
/*
Motion-Sensing Warning Lights
This sketch will wait for a high input on D2 from the PIR motion
sensor, and then flash WiFi-connected lights to alert the room.
Circuit:
HC-SR501 PIR motion sensor attached, input on digital pin 2
created 30 July 2020
by Matt Taylor
*/
#include <SPI.h>
#include <WiFiNINA.h>
#include <WiFiUdp.h>
#include <ArduinoJson.h>
#include "arduino_secrets.h"
int status = WL_IDLE_STATUS;
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
const char SSID[] = SECRET_SSID; // your network SSID (name)
const char PASS[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP)
const int KEY_INDEX = 0; // your network key Index number (needed only for WEP)
const int MOTION_PIN = 2; // motion is read on digital pin 2
const unsigned int LOCAL_PORT = 2444; // the UDP port to use for the arduino
const unsigned int LIGHT_PORT = 38899; // the UDP port the lights are listening on; change this to fit your lights
// The static IPs of the lights
// Change these to match the (preferably static) IPs of the WiZ-enabled lights you're using.
// You can use any arbitrary number of lights and the program will work the same.
const IPAddress LIGHTS[] = { IPAddress(192, 168, 1, 64), IPAddress(192, 168, 1, 65) };
const char GET_BUFFER[] = "{\"method\":\"getPilot\"}"; // packet to get the state of a light
const char ON_BUFFER[] = "{\"method\":\"setPilot\",\"params\":{\"state\": 1}}"; // packet to turn off a light
const char OFF_BUFFER[] = "{\"method\":\"setPilot\",\"params\":{\"state\": 0}}"; // packet to turn off a light
char packetBuffer[255];
WiFiUDP Udp;
void setup() {
// Set the motion sensor's pin to input mode
pinMode(MOTION_PIN, INPUT);
//Initialize serial
Serial.begin(9600);
Serial.print("Targeting the following lights on port: ");
Serial.println(LIGHT_PORT);
for (const IPAddress& lightIP : LIGHTS) {
Serial.println(lightIP);
}
String fv = WiFi.firmwareVersion();
if (fv != "1.3.0") {
Serial.println("Please upgrade the firmware");
Serial.print("Currently on version ");
Serial.println(fv);
}
// attempt to connect to Wifi network:
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(SSID);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(SSID, PASS);
// wait 5 seconds for connection:
delay(5000);
}
Serial.println("Connected to WiFi");
printWifiStatus();
Serial.println("Waiting for motion...");
Udp.begin(LOCAL_PORT);
}
void packetFlush() {
// parse all packets in the RX buffer to clear it
while (Udp.parsePacket()) {
;
}
}
bool areLightsOn() {
bool lightsOn = true;
for (const IPAddress& lightIP : LIGHTS) {
if (!isLightOn(lightIP, LIGHT_PORT)) {
// toggle this value to false if any one light in the array is turned off
lightsOn = false;
}
}
Serial.print("Are lights on? ");
Serial.println(lightsOn ? "Yes" : "No");
// if this is still true, it means every light was on
return lightsOn;
}
bool isLightOn(const IPAddress& lightIP, const uint16_t& lightPort) {
bool lightOn = false;
// flush RX buffer to avoid reading old packets
packetFlush();
Udp.beginPacket(lightIP, lightPort);
Udp.write(GET_BUFFER);
Udp.endPacket();
int packetSize = Udp.parsePacket();
int timeout = 100;
while (!packetSize && timeout > 0) {
// wait until a reply is sent
packetSize = Udp.parsePacket();
timeout--;
delay(200);
}
if (timeout == 0) {
Serial.print("Error: light timed out: ");
Serial.print(lightIP);
Serial.print(" on port ");
Serial.println(lightPort);
return false;
}
if (packetSize) {
// read the packet into packetBufffer
int len = Udp.read(packetBuffer, 255);
if (len > 0) {
packetBuffer[len] = 0;
}
Serial.println("Packet received: ");
Serial.println(packetBuffer);
// declare a JSON document to hold the response
const int capacity = JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(7);
StaticJsonDocument<capacity> response;
// get the current state of the light, whether it's on or off
DeserializationError err = deserializeJson(response, packetBuffer);
if (err.code() == DeserializationError::Ok) {
lightOn = response["result"]["state"];
}
}
return lightOn;
}
void loop() {
// if motion is detected, flash the lights
if (digitalRead(MOTION_PIN) == HIGH) {
Serial.println("Motion detected, checking lights");
if (areLightsOn()) {
Serial.println("Flashing lights");
// flash the lights twice
int i = 0;
while (i < 2) {
// turn all the lights off
for (const IPAddress& lightIP : LIGHTS) {
Udp.beginPacket(lightIP, LIGHT_PORT);
Udp.write(OFF_BUFFER);
Udp.endPacket();
}
// wait this long to turn the lights back on
delay(500);
// turn them back on
for (const IPAddress& lightIP : LIGHTS) {
Udp.beginPacket(lightIP, LIGHT_PORT);
Udp.write(ON_BUFFER);
Udp.endPacket();
}
delay(500);
i++;
}
}
// cooldown for four seconds
Serial.println("Cooling down...");
delay(4000);
Serial.println("Ready for motion");
}
}
void printWifiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your WiFi module's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment