|
#include <WiFi.h> |
|
#include <ArduinoJson.h> |
|
#include <HTTPClient.h> |
|
HTTPClient http; |
|
|
|
// Parse JSON response |
|
DynamicJsonDocument doc(1024); |
|
|
|
const int motionPin = 2; // GPIO pin connected the OUT pin of the AM312 sensor to |
|
const int led1Pin = 13; // Replace with the pin of the first LED (green) |
|
const int led2Pin = 15; // Replace with the pin of the second LED (red) |
|
int time_idle = 0; |
|
int time_in_motion = 0; |
|
|
|
const char *ssid = "wifi-ssid"; |
|
const char *password = "wifi-password"; |
|
|
|
const char *apiKey = "govee-api-key"; // get api key from govee |
|
const char *url = "https://developer-api.govee.com/v1/devices"; |
|
const char *control_endpoint = "https://developer-api.govee.com/v1/devices/control"; |
|
const String &state_endpoint = "https://developer-api.govee.com/v1/devices/state"; |
|
|
|
|
|
// devices that we want to turn on and off |
|
const char *devicesToControl[] = { "[1] Smart LED Bulb", "[2] Smart LED Bulb", "[3] Smart LED Bulb", "[4] Smart LED Bulb" }; |
|
bool getDevicesSuccess = false; |
|
|
|
|
|
struct DeviceState { |
|
String powerState; |
|
bool online; |
|
}; |
|
|
|
|
|
void setup() { |
|
Serial.begin(115200); |
|
pinMode(motionPin, INPUT); |
|
|
|
pinMode(led1Pin, OUTPUT); |
|
pinMode(led2Pin, OUTPUT); |
|
|
|
delay(10); |
|
|
|
// Connect to Wi-Fi |
|
Serial.println(); |
|
Serial.print("Connecting to "); |
|
Serial.println(ssid); |
|
|
|
WiFi.begin(ssid, password); |
|
|
|
while (WiFi.status() != WL_CONNECTED) { |
|
delay(1000); |
|
Serial.print("."); |
|
} |
|
|
|
Serial.println(""); |
|
Serial.println("WiFi connected"); |
|
Serial.println("IP address: "); |
|
Serial.println(WiFi.localIP()); |
|
|
|
delay(1000); |
|
getDevices(); |
|
delay(5000); |
|
} |
|
|
|
// Function to turn on LED1 and turn off LED2 |
|
void turn1on2off() { |
|
digitalWrite(led1Pin, HIGH); |
|
digitalWrite(led2Pin, LOW); |
|
} |
|
|
|
// Function to turn on LED2 and turn off LED1 |
|
void turn2on1off() { |
|
digitalWrite(led1Pin, LOW); |
|
digitalWrite(led2Pin, HIGH); |
|
} |
|
|
|
void loop() { |
|
int motionState = digitalRead(motionPin); |
|
|
|
if (motionState == HIGH) { |
|
Serial.print("Motion detected! - "); |
|
Serial.print("Motion lasted "); |
|
Serial.print(time_in_motion); |
|
Serial.println(" s."); |
|
time_in_motion++; |
|
time_idle = 0; |
|
if(time_in_motion == 4) { |
|
printDevices("on"); |
|
} |
|
turn1on2off(); |
|
|
|
} else { |
|
Serial.print("No motion! - "); |
|
Serial.print("Idleness lasted "); |
|
Serial.print(time_idle); |
|
Serial.println(" s."); |
|
time_in_motion = 0; |
|
time_idle++; |
|
if(time_idle == 4) { |
|
printDevices("off"); |
|
} |
|
turn2on1off(); |
|
} |
|
|
|
delay(1000); // 1s delay |
|
} |
|
|
|
void getDevices() { |
|
HTTPClient http; |
|
|
|
Serial.print("Sending GET request to Govee API..."); |
|
|
|
// Your Govee API URL |
|
http.begin(url); |
|
|
|
// Set headers |
|
http.addHeader("Govee-API-Key", apiKey); |
|
|
|
// Send the request |
|
int httpCode = http.GET(); |
|
|
|
if (httpCode > 0) { |
|
Serial.printf("[HTTP] GET... code: %d\n", httpCode); |
|
|
|
if (httpCode == HTTP_CODE_OK) { |
|
String payload = http.getString(); |
|
Serial.println(payload); |
|
deserializeJson(doc, payload); |
|
|
|
getDevicesSuccess = true; // a successful API call |
|
|
|
int numDevicesToControl = sizeof(devicesToControl) / sizeof(devicesToControl[0]); |
|
|
|
|
|
// Extract and print device information |
|
JsonArray devices = doc["data"]["devices"]; |
|
for (JsonObject device : devices) { |
|
const char *deviceName = device["deviceName"]; |
|
const char *device_address = device["device"]; |
|
for (int i = 0; i < numDevicesToControl; i++) { |
|
|
|
if (strcmp(deviceName, devicesToControl[i]) == 0) { |
|
|
|
const char *model = device["model"]; |
|
bool controllable = device["controllable"]; |
|
bool retrievable = device["retrievable"]; |
|
|
|
Serial.println("Device Name: " + String(deviceName) + " " + String(device_address)); |
|
Serial.println("Model: " + String(model)); |
|
Serial.println("Controllable: " + String(controllable ? "Yes" : "No")); |
|
Serial.println("Retrievable: " + String(retrievable ? "Yes" : "No")); |
|
Serial.println("------"); |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
} else { |
|
Serial.printf("[HTTP] GET request failed, error: %s\n", http.errorToString(httpCode).c_str()); |
|
} |
|
|
|
// Free resources |
|
http.end(); |
|
} |
|
|
|
void printDevices(const String &action) { |
|
// Check if the API call was successful before printing devices |
|
if (getDevicesSuccess) { |
|
// Extract and print device information |
|
JsonArray devices = doc["data"]["devices"]; |
|
for (JsonObject device : devices) { |
|
const char *deviceName = device["deviceName"]; |
|
const char *device_address = device["device"]; |
|
const char *model = device["model"]; |
|
bool controllable = device["controllable"]; |
|
bool retrievable = device["retrievable"]; |
|
|
|
DeviceState state = getDeviceState(device_address, model); |
|
|
|
Serial.println("Device Name: " + String(deviceName)); |
|
Serial.println("Model: " + String(model)); |
|
|
|
Serial.println("Power State: " + state.powerState); |
|
Serial.println("Online: " + String(state.online ? "Yes" : "No")); |
|
if(state.online) { |
|
// then we can either turn on or off |
|
|
|
if(action != state.powerState) { |
|
controlDevice(device_address, model, "turn", action); |
|
Serial.println("[ACTION] Turn " + String(action)); |
|
} else { |
|
Serial.println("do nothing..."); |
|
} |
|
} |
|
|
|
// Serial.println("Controllable: " + String(controllable ? "Yes" : "No")); |
|
// Serial.println("Retrievable: " + String(retrievable ? "Yes" : "No")); |
|
Serial.println("------"); |
|
} |
|
} else { |
|
Serial.println("API call was not successful. Check the previous logs for details."); |
|
} |
|
} |
|
|
|
void controlDevice(const String &device, const String &model, const String &cmdName, const String &cmdValue) { |
|
HTTPClient http; |
|
|
|
Serial.print("[CONTROL DEVICE]"); |
|
http.begin(control_endpoint); |
|
http.addHeader("Content-Type", "application/json"); |
|
http.addHeader("Govee-API-Key", apiKey); |
|
|
|
// Create JSON request body |
|
StaticJsonDocument<200> jsonBody; |
|
jsonBody["device"] = device; |
|
jsonBody["model"] = model; |
|
|
|
JsonObject cmdObject = jsonBody.createNestedObject("cmd"); |
|
cmdObject["name"] = cmdName; |
|
cmdObject["value"] = cmdValue; |
|
|
|
// Serialize JSON to string |
|
String jsonString; |
|
serializeJson(jsonBody, jsonString); |
|
|
|
// Send the request |
|
int httpCode = http.PUT(jsonString); |
|
|
|
if (httpCode > 0) { |
|
// HTTP header has been sent and the response status code received |
|
Serial.printf("[HTTP] PUT... code: %d\n", httpCode); |
|
|
|
// File found at the server |
|
if (httpCode == HTTP_CODE_OK) { |
|
String payload = http.getString(); |
|
Serial.println(payload); |
|
} |
|
} else { |
|
Serial.printf("[HTTP] PUT request failed, error: %s\n", http.errorToString(httpCode).c_str()); |
|
} |
|
|
|
// Free resources |
|
http.end(); |
|
} |
|
|
|
DeviceState getDeviceState(const String &device, const String &model) { |
|
HTTPClient http; |
|
|
|
Serial.print("[GET STATE]"); |
|
|
|
String apiUrl = state_endpoint + "?device=" + device + "&model=" + model; |
|
http.begin(apiUrl); |
|
|
|
// Set headers |
|
http.addHeader("Govee-API-Key", apiKey); |
|
|
|
DeviceState result; // Create a struct to store the result |
|
|
|
// Send the request |
|
int httpCode = http.GET(); |
|
|
|
if (httpCode > 0) { |
|
Serial.printf("[HTTP] GET... code: %d\n", httpCode); |
|
|
|
if (httpCode == HTTP_CODE_OK) { |
|
String payload = http.getString(); |
|
Serial.println(payload); |
|
|
|
// Parse JSON response |
|
DynamicJsonDocument doc(1024); |
|
deserializeJson(doc, payload); |
|
|
|
// Extract device state information |
|
JsonObject data = doc["data"]; |
|
result.powerState = data["properties"][1]["powerState"].as<String>(); |
|
result.online = data["properties"][0]["online"]; |
|
} |
|
} else { |
|
Serial.printf("[HTTP] GET request failed, error: %s\n", http.errorToString(httpCode).c_str()); |
|
} |
|
|
|
// Free resources |
|
http.end(); |
|
|
|
return result; |
|
} |