In an era of advancing technology, the integration of smart solutions into our urban infrastructure is becoming increasingly essential. Smart street lighting systems represent one such innovation aimed at optimizing energy usage, enhancing safety, and reducing operational costs. This technical project proposes the design and implementation of a smart street lighting system equipped with auto on-off functionality and a power consumption meter.
Objectives:- Develop a robust and energy-efficient smart street lighting system.
- Implement automatic on-off functionality based on environmental conditions and time schedules.
- Integrate remote control commands for manual adjustments and monitoring.
- Incorporate a power consumption meter to track energy usage and optimize efficiency.
- Enhance reliability and longevity of street lighting infrastructure.
- AVR-IoT Cellular Mini: The AVR-IoT Cellular Mini development board features the Microchip AVR128DB48 AVR® microcontroller and ATECC608B secure element for IoT solution development, with included Truphone SIM card for data activation and hardware authentication capability.
- ACS712: ACS712 offers cost-effective and accurate AC/DC current sensing for industrial, commercial, and communication systems.
- 5v Relay: This switch controls the circuit electromechanically, allowing electrical appliances to be turned on and off with a low power signal.
- Connect the ACS712 current sensor to analog pin A0 and the voltage sensor to analog pin A1.
- Connect the relay module to digital pin 8.
- Insert the Truphone SIM card into the LTE module.
- Connect the Arduino to the LTE module and other peripherals.
- Define constants for sensor pins, MQTT topics, MQTT credentials, and other parameters.
- Initialize the Arduino, LTE module, MQTT client, and other necessary components in the
setup()
function.
Functionality:
- Current and Voltage Sensing:
The ACS712 current sensor measures AC or DC current with high precision.
Voltage sensing is achieved using a voltage divider connected to analog pin A1. - MQTT Messaging:
Subscribe to MQTT topics for receiving control commands and sending sensor data.
Process incoming MQTT messages to control the relay and request sensor data. - LTE Connectivity:
Establish LTE connectivity using the LTE module.
Monitor LTE connection status and attempt reconnection if necessary. - NTP Time Synchronization:
Synchronize time with an NTP server to ensure accurate timekeeping.
Perform actions based on specific times, such as toggling the relay.
https://github.com/ddmakadia1699/The-Future-of-Resilience-Contest-with-Microchip/tree/main
Arduino code:#include <ecc608.h>
#include <led_ctrl.h>
#include <log.h>
#include <lte.h>
#include <mqtt_client.h>
#include "ACS712.h"
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
Libraries:
ecc608.h
: Library for interfacing with the ECC608 secure element (optional)led_ctrl.h
: Library for controlling LEDs (optional)log.h
: Library for logging messages to a serial interfacelte.h
: Library for LTE connectivitymqtt_client.h
: Library for MQTT messagingACS712.h
: Library for interfacing with the ACS712 current sensorSPI.h
: Library for SPI communicationEthernet.h
: Library for Ethernet connectivityEthernetUdp.h
: Library for UDP communication
#define CURRENT_SENSOR_PIN A0
#define VOLTAGE_SENSOR_PIN A1
#define RELAY_PIN 8
#define RESISTOR_VALUE 10000.0 // Resistance value of voltage divider resistor in Ohms
// #define ACS712_SENSITIVITY 66.0 // Sensitivity of ACS712 sensor (mV/A for ACS712-20A)
#define MQTT_SUB_TOPIC "Control"
#define MQTT_SUB_COMMON_TOPIC "Common"
#define MQTT_PUB_TOPIC "publish"
#define MQTT_THING_NAME "12345"
#define MQTT_BROKER "tailor.cloudmqtt.com"
#define MQTT_PORT 13582
#define MQTT_USE_TLS false
#define MQTT_KEEPALIVE 60
#define MQTT_USE_ECC false
#define MOSQUITTO_USERNAME "ffbqwwfa"
#define MOSQUITTO_PASSWORD "abcdefgh"
#define MAX_MESSAGE_LENGTH 256
char message_buff[MAX_MESSAGE_LENGTH]; // Define the message buffer
// ACS712 sensor(ACS712_20A, CURRENT_SENSOR_PIN); // Create an ACS712 object for a 20A sensor
// 5.0 volt with a max ADC value of 1023 steps
ACS712 ACS(A0, 5.0, 1023, 100);
static volatile bool connecteded_to_network = false;
static volatile bool connected_to_broker = false;
// Enter a MAC address for your controller below.
byte mac[] = { 0xD0, 0x12, 0xBE, 0x6F, 0x1E, 0x9D };
// Set the IP address of the Arduino
IPAddress ip(192, 168, 1, 177);
// NTP Servers:
IPAddress timeServer(132, 163, 96, 1); // time.nist.gov
// NTP time stamp is in the first 48 bytes of the message
const unsigned int NTP_PACKET_SIZE = 48;
byte packetBuffer[NTP_PACKET_SIZE];
// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
unsigned long lastSyncTime = 0; // Last time synced with NTP server
const unsigned long syncInterval = 30000; // Sync interval in milliseconds (30 seconds)
In the provided code snippet, several lines are crucial for setting up the IoT system. Initially, pins and parameters are defined for sensors, the relay, and MQTT communication. Following this, MQTT topics, broker details, and message length are specified to establish communication protocols. Subsequently, a buffer is created to store incoming MQTT messages efficiently.
The ACS712 current sensor is then initialized to accurately measure current levels in the system. Additionally, network and MQTT connection statuses are tracked to ensure seamless communication. MAC and IP addresses are assigned to the Arduino for network connectivity, while the NTP server address and packet size are specified for time synchronization purposes.
Moreover, a UDP object is declared for NTP communication, allowing the device to synchronize time effectively. Lastly, the last synchronization time and interval are stored to manage periodic synchronization with the NTP server. These lines collectively play pivotal roles in configuring settings, declaring variables, and initializing objects essential for the smooth operation of the IoT system.
void disconnectedFromBroker(void) {
connected_to_broker = false;
}
void disconnectedFromNetwork(void) {
connecteded_to_network = false;
}
static bool connectLTE() {
// Connect with a maximum timeout value of 30 000 ms, if the connection is
// not up and running within 30 seconds, abort and retry later
if (!Lte.begin(30000)) {
return false;
} else {
return true;
}
}
The provided code defines three functions: disconnectedFromBroker
, disconnectedFromNetwork
, and connectLTE
.
The disconnectedFromBroker
function is responsible for handling disconnection events from the MQTT broker. When called, it sets the connected_to_broker
variable to false
, indicating that the device is no longer connected to the MQTT broker.
Similarly, the disconnectedFromNetwork
function handles disconnection events from the network. It sets the connected_to_network
variable to false
upon execution, signifying that the device has lost its network connection.
The connectLTE
function attempts to establish a connection to the LTE network. It sets a maximum timeout value of 30,000 milliseconds for the connection attempt. If the connection is not established within this timeframe, the function returns false
, indicating a failed connection attempt. Otherwise, if the connection is successfully established, the function returns true
.
These functions are essential for managing network connections and handling disconnection events in an IoT system, ensuring robust connectivity and reliability.
static bool connectMqtt() {
// Attempt to connect to the broker
if (!MqttClient.begin(MQTT_THING_NAME,
MQTT_BROKER,
MQTT_PORT,
MQTT_USE_TLS,
MQTT_KEEPALIVE,
MQTT_USE_ECC,
MOSQUITTO_USERNAME,
MOSQUITTO_PASSWORD)) {
return false;
}
return true;
}
void onMqttMessage(char* topic, char* payload, unsigned int length) {
Serial.print("Message arrived on topic: ");
Serial.println(topic);
// Clear the buffer
memset(message_buff, 0, sizeof(message_buff));
// Copy payload into message_buff
for (unsigned int i = 0; i < length && i < MAX_MESSAGE_LENGTH - 1; i++) {
message_buff[i] = payload[i];
}
// Ensure null-termination of the string
message_buff[length < MAX_MESSAGE_LENGTH ? length : MAX_MESSAGE_LENGTH - 1] = '\0';
Serial.print("Message received: ");
Serial.println(message_buff);
if (strcmp(message_buff, "meterdata") == 0) {
// if(message_buff == "meterdata"){
// Read current in mA
float current = ACS.mA_AC();
// Read voltage using voltage divider
int rawVoltage = analogRead(VOLTAGE_SENSOR_PIN);
float voltage = (rawVoltage / 1023.0) * 5.0; // Convert raw value to voltage
voltage *= (RESISTOR_VALUE + 1000.0) / 1000.0; // Adjust voltage based on voltage divider ratio
// Calculate power
float power = voltage * (current / 1000.0); // Power in Watts
// Calculate energy consumed over time (in Wh)
float energy = power / 3600.0; // Assuming 1-hour resolution (3600 seconds)
// Print readings
Serial.print("Current (mA): ");
Serial.print(current);
Serial.print("\tVoltage (V): ");
Serial.print(voltage);
Serial.print("\tPower (W): ");
Serial.print(power);
Serial.print("\tEnergy (Wh): ");
Serial.println(energy);
}
if (strcmp(topic, "Control") == 0) {
if (strcmp(message_buff, "on") == 0) {
digitalWrite(RELAY_PIN, HIGH);
} else if (strcmp(message_buff, "off") == 0) {
digitalWrite(RELAY_PIN, LOW);
}
}
}
The connectMqtt
function attempts to establish a connection to the MQTT broker. It uses the parameters provided, such as the MQTT Thing name, broker address, port, TLS usage, keepalive interval, ECC usage, and MQTT username/password. If the connection is successful, the function returns true
; otherwise, it returns false
.
The onMqttMessage
function is an event handler invoked when a message is received on the MQTT topic subscribed to. It takes parameters for the topic, payload, and payload length. Upon receiving a message, it prints the topic and message payload to the serial interface. It then processes the message, checking if it matches "meterdata". If so, it reads current and voltage data from sensors, calculates power and energy consumption, and prints the readings to the serial interface.
Additionally, if the topic is "Control", it checks the message payload. If the payload is "on", it sets the relay pin to HIGH, turning the relay ON. If the payload is "off", it sets the relay pin to LOW, turning the relay OFF. This allows for remote control of devices connected to the relay based on MQTT messages.
void setup() {
Log.begin(115200);
Ethernet.begin(mac, ip);
LedCtrl.begin();
LedCtrl.startupCycle();
pinMode(RELAY_PIN, OUTPUT);
// Initialize UDP
Udp.begin(8888);
Log.info(F("Starting MQTT with username and password example"));
// Establish LTE connection
if (!Lte.begin()) {
Log.error(F("Failed to connect to operator"));
// Halt here
while (1) {}
}
// Attempt to connect to the broker
if (MqttClient.begin(MQTT_THING_NAME,
MQTT_BROKER,
MQTT_PORT,
MQTT_USE_TLS,
MQTT_KEEPALIVE,
MQTT_USE_ECC,
MOSQUITTO_USERNAME,
MOSQUITTO_PASSWORD)) {
if (MqttClient.subscribe(MQTT_SUB_TOPIC)) {
Log.infof(F("Subscribed to %s\r\n"), MQTT_SUB_TOPIC);
} else {
Log.error(F("Failed to subscribe to topic"));
// Halt here
while (1) {}
}
if (MqttClient.subscribe(MQTT_SUB_COMMON_TOPIC)) {
Log.infof(F("Subscribed to %s\r\n"), MQTT_SUB_COMMON_TOPIC);
} else {
Log.error(F("Failed to subscribe to topic"));
// Halt here
while (1) {}
}
} else {
// Halt here
while (1) {}
}
// Log.info("Closing MQTT connection");
// MqttClient.end();
Lte.onDisconnect(disconnectedFromNetwork);
MqttClient.onDisconnect(disconnectedFromBroker);
}
void loop() {
if (!connecteded_to_network) {
Log.info(F("Not connected to the network. Attempting to connect!"));
if (connectLTE()) {
connecteded_to_network = true;
}
}
if (!connected_to_broker && connecteded_to_network) {
Log.info(F("Not connected to broker. Attempting to connect!"));
if (connectMqtt()) {
connected_to_broker = true;
}
}
MqttClient.readMessage(MQTT_SUB_TOPIC);
MqttClient.readMessage(MQTT_SUB_COMMON_TOPIC);
unsigned long currentTime = millis();
// Check if it's time to sync with the NTP server
if (currentTime - lastSyncTime >= syncInterval || lastSyncTime == 0) {
// Sync with NTP server
sendNTPpacket(timeServer);
lastSyncTime = currentTime;
}
// Check if data is available to be read
if (Udp.parsePacket()) {
Serial.println("Received NTP Response");
// Read packet into the buffer
Udp.read(packetBuffer, NTP_PACKET_SIZE);
// Extract the timestamp
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
unsigned long secsSince1900 = highWord << 16 | lowWord;
// Subtract 70 years (Unix epoch starts on Jan 1, 1970)
const unsigned long seventyYears = 2208988800UL;
unsigned long epoch = secsSince1900 - seventyYears;
// Print the time
Serial.print("Unix Epoch Time: ");
Serial.println(epoch);
// Get the current hour
int currentHour = (epoch % 86400L) / 3600; // 86400 seconds in a day, 3600 seconds in an hour
// Check if it's 6 PM
if (currentHour == 18) { // 6 PM
digitalWrite(RELAY_PIN, HIGH);
} else {
digitalWrite(RELAY_PIN, LOW);
}
if (currentHour == 6) { // 6 AM
digitalWrite(RELAY_PIN, LOW);
} else {
digitalWrite(RELAY_PIN, HIGH);
}
}
}
In the setup()
function, the program initializes various components necessary for its operation. First, it sets up serial communication at a baud rate of 115200 for debugging and monitoring purposes. Then, it establishes an Ethernet connection using the provided MAC and IP addresses. Afterward, it initializes LED control and performs a startup cycle. The pin mode for the relay pin is set as OUTPUT to control the relay. UDP communication is initialized on port 8888. Subsequently, the program attempts to establish an LTE connection. If the LTE connection fails, an error message is logged, and the program halts. Next, the program attempts to connect to the MQTT broker using the specified credentials. If the connection is successful, the program subscribes to MQTT topics for receiving messages. However, if the MQTT connection attempt fails, the program halts to prevent further execution.
In the loop()
function, the program continuously executes the main logic. It first checks if the device is connected to the network and attempts to establish an LTE connection if not already connected. Then, it verifies if the device is connected to the MQTT broker and attempts to establish an MQTT connection if the network connection is established but the MQTT connection is not. The program reads messages from MQTT subscribed topics. Additionally, it periodically synchronizes time with the NTP server to ensure accurate timekeeping. If an NTP response is received, the Unix epoch time is extracted, and based on the current hour, the relay pin is controlled accordingly, turning it ON at 6 PM and OFF at 6 AM. This loop continues to execute indefinitely, ensuring continuous monitoring and control of the IoT system's functionality.
RequiredAccount:
1. AWS account (https://aws.amazon.com/)
2. Alexa Developer (https://developer.amazon.com/en-US/alexa)
3. Google Cloud Developer (https://console.cloud.google.com)
To develop an Amazon Alexa smart home skill, you can follow the steps provided in the video. Be sure to set up a rule that enables the Lambda function to read data from DynamoDB, which will give you the ability to display real-time switch statuses in both the Amazon Alexa and Google Home applications.
AWS Role :
Also change runtime setting in lambda function. Edit handler lambda_function to only lambda (if you copy paste my code).
Google action :
Account linking and setup for google action :
With the completion of this project, you now have functional smart streetlights with energy consumption monitoring that can be controlled using voice commands through Amazon Alexa and Google Home.
Comments