Wen-Liang Lin
Published © GPL3+

Portable street light monitoring system

A small box that monitors the brightness of street lights and transmits the brightness back to the cloud.

BeginnerWork in progress2 hours180

Things used in this project

Hardware components

AVR IoT Mini Cellular Board
Microchip AVR IoT Mini Cellular Board
×1

Software apps and online services

Arduino IDE
Arduino IDE
Adafruit IO

Story

Read more

Code

Light_sensor_adafruitio_MQTT.ino

Arduino
/***************************************************
  Adafruit MQTT Library WINC1500 Example

  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  MIT license, all text above must be included in any redistribution
 ****************************************************/
#include <SPI.h>
#include <ecc608.h>
#include <mqtt_client.h>

#include <stdlib.h>
#include <EEPROM.h>
//#include <TimeLib.h>

#include <Arduino.h>
#include <led_ctrl.h>
#include <log.h>
#include <low_power.h>
#include <lte.h>
#include <mcp9808.h>
#include <veml3328.h>

#define SerialCDC Serial3
/************************* Adafruit.io Setup *********************************/
#define AIO_SERVER "io.adafruit.com"
#define AIO_SERVERPORT 1883
// #define AIO_USERNAME ""
// #define AIO_KEY ""
#define MQTT_THING_NAME    "JustName"
#define MQTT_BROKER        "io.adafruit.com" //AIO_SERVER
#define MQTT_PORT          1883 //AIO_SERVERPORT
#define MQTT_USE_TLS       false
#define MQTT_KEEPALIVE     60
#define MQTT_USE_ECC       false
#define MOSQUITTO_USERNAME "AIO_USERNAME" //AIO_USERNAME
#define MOSQUITTO_PASSWORD "AIO_KEY" //AIO_KEY



/****************************** Feeds ***************************************/

// // Setup a feed called 'photocell' for publishing.
// // Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname>
// Adafruit_MQTT_Publish location = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/street-light-monitor.location/csv");

// // Setup a feed called 'onoff' for subscribing to changes.
// Adafruit_MQTT_Subscribe light_value = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/street-light-monitor.light-value");

// Adafruit_MQTT_Subscribe Realtime = Adafruit_MQTT_Subscribe(&mqtt, "time/seconds");

#define MQTT_SUB_TOPIC "time/seconds"
#define MQTT_PUB_TOPIC "momososo/feeds/street-light-monitor.location/csv"

/************ Global State (you don't need to change this!) ******************/

// Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);

// You don't need to change anything below this line!
#define halt(s)              \
  {                          \
    SerialCDC.println(F(s)); \
    while (1)                \
      ;                      \
  }


/*************************** Sketch Code ************************************/

// this value integer will hold the current count value for our sketch
int sensorvalue = 0;

int txfailures = 0;
// these float values will hold our fake GPS data
#define EEaddrlat 0
#define EEaddrlon 4
#define EEaddrele 8
float lat1 = 24.148730f;
float lon1 = 120.665125f;
float ele = 0.00f;
char sendbuffer[128];
uint32_t unixTimeStamp;
const int timeZone = 8;

bool User_SW_f = false;
String inputString = "";     // a String to hold incoming data
bool stringComplete = false; // whether the string is complete
unsigned long Timer_from2;

void setup()
{
  LedCtrl.begin();
  LedCtrl.startupCycle();
  Log.begin(115200);
  Log.setLogLevel(LogLevel::INFO);

  pinConfigure(PIN_PD2, PIN_DIR_INPUT | PIN_PULLUP_ON);

  inputString.reserve(200);


  EEPROM.get(EEaddrlat, lat1);
  EEPROM.get(EEaddrlon, lon1);
  EEPROM.get(EEaddrele, ele);
  SerialCDC.print(F("Location:"));
  SerialCDC.print(lat1);
  SerialCDC.print(",");
  SerialCDC.print(lon1);
  SerialCDC.print(",");
  SerialCDC.println(ele);

  if (Mcp9808.begin()) {
    Log.error(F("Could not start MCP9808."));
    return false;
  }
  Mcp9808.shutdown();

  if (Veml3328.begin())
  {
    Log.error(F("Error: could not start VEML3328 library"));
  }

  SerialCDC.printf("Device ID: %x\r\n", Veml3328.deviceID());
  sensorvalue = Veml3328.getClear();

  User_SW_f = digitalRead(PIN_PD2);
  if (!User_SW_f)
  {
    Log.infof(F("UART location setting mode"));
    Log.infof(F("Use \"lat:ddd.ddd\" to set latitude"));
    Log.infof(F("Use \"lon:ddd.ddd\" to set longitude"));
    Log.infof(F("Use \"ele:ddd.ddd\" to set elevation"));
    Log.infof(F("Use \"exit!\" to exit"));
    Log.infof(F("!!!Auto exit after 180 secons!!!"));
  }
  while (((millis() - Timer_from2) < 180000) && !User_SW_f )
  {
    UART_locationsetting();
  }

  // Now we configure the low power module for power down configuration, where
  // the cellular modem and the CPU will be powered down
  LowPower.configurePowerDown();
}

uint32_t x = 0;

void loop()
{
  SerialCDC.printf("Device ID: %x\r\n", Veml3328.deviceID());
  delay(100);
  sensorvalue = Veml3328.getClear();
  SerialCDC.println(sensorvalue);

  MQTT_main();

  Veml3328.shutdown();

  Log.info(F("Powering down..."));
  // Power down for 1 hrs
  LowPower.powerDown(3600);
  Log.info(F("wake up!"));
  Veml3328.wake();


}

void MQTT_main() {

  // Ensure the connection to the MQTT server is alive (this will make the first
  // connection and automatically reconnect when disconnected).  See the MQTT_connect
  // function definition further below.
  MQTT_connect();


  // Now we can publish stuff!
  MQTT_publocation();
}

// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect() {
  int8_t ret;

  // Check first if we are connected to the operator. We might get
  // disconnected, so for our application to continue to run, we double check
  // here
  if (!Lte.isConnected()) {

    // Attempt to connect to the operator
    if (!Lte.begin()) {
      return;
    } else {
      Log.infof(F("Connected to operator %s\r\n"),
                Lte.getOperator().c_str());
    }
  }

  if (Lte.isConnected())
  {
    // Stop if already connected.
    if (!MqttClient.isConnected())
    {
      if (!MqttClient.begin(MQTT_THING_NAME, MQTT_BROKER, MQTT_PORT, MQTT_USE_TLS, MQTT_KEEPALIVE, MQTT_USE_ECC, MOSQUITTO_USERNAME, MOSQUITTO_PASSWORD))
      {
        Log.error(F("Failed to connect to MQTT."));
      }
    }
  }

}


void MQTT_publocation() {
  Serial.print("GSMLoc lat:");
  Serial.println(lat1);
  Serial.print("GSMLoc lon:");
  Serial.println(lon1);
  sprintf(sendbuffer, "%d,%.7f,%.7f,%.7f", sensorvalue, lat1, lon1, ele);
  Serial.print("Sending: ");
  Serial.println(sendbuffer);
  bool publishedSuccessfully =
    MqttClient.publish(MQTT_PUB_TOPIC, sendbuffer);

  if (publishedSuccessfully) {
    Log.infof(F("Published Success\r\n"));
  } else {
    Log.error(F("Failed to publish"));
  }
}

/*
// use to display date and time I have test witn wifi device but not use here
void digitalClockDisplay() {
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year());
  Serial.println();
}
void printDigits(int digits) {
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(':');
  if (digits < 10)
    Serial.print('0');
  Serial.print(digits);
}
*/

// USB CDC RX not working need to add serialEvent() into loop()
/*
  Serial Event example

  When new serial data arrives, this sketch adds it to a String.
  When a newline is received, the loop prints the string and clears it.

  A good test for this is to try it with a GPS receiver that sends out
  NMEA 0183 sentences.

  NOTE: The serialEvent() feature is not available on the Leonardo, Micro, or
  other ATmega32U4 based boards.

  created 9 May 2011
  by Tom Igoe

  This example code is in the public domain.

  https://www.arduino.cc/en/Tutorial/BuiltInExamples/SerialEvent
*/
void serialEvent()
{
  while (SerialCDC.available())
  {
    // get the new byte:
    char inChar = (char)SerialCDC.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag so the main loop can
    // do something about it:
    if (inChar == '\n')
    {
      stringComplete = true;
    }
  }
}

void UART_locationsetting()
{
  serialEvent();

  if (stringComplete)
  {
    SerialCDC.println(inputString);

    // send "lat:123.456" for setting latitude
    if (inputString.startsWith("lat:"))
    {
      String sub_S = inputString.substring(4, inputString.length()); // from 4 to end
      //      SerialCDC.println(sub_S);
      lat1 = sub_S.toDouble();
      EEPROM.put(EEaddrlat, lat1);
    }

    // send "lon:123.456" for setting longitude
    if (inputString.startsWith("lon:"))
    {
      String sub_S = inputString.substring(4, inputString.length()); // from 4 to end
      //   SerialCDC.println(sub_S);
      lon1 = sub_S.toDouble();
      EEPROM.put(EEaddrlon, lon1);
    }

    // send "ele:1.00" for setting elevation
    if (inputString.startsWith("ele:"))
    {
      String sub_S = inputString.substring(4, inputString.length()); // from 4 to end
      //   SerialCDC.println(sub_S);
      ele = sub_S.toDouble();
      EEPROM.put(EEaddrele, ele);
    }

    // send "exit!" to exit
    if (inputString.startsWith("exit!"))
    {
      SerialCDC.println(F("exit!"));
      User_SW_f = 1;
    }

    SerialCDC.print(F("Location update:"));
    SerialCDC.print(lat1);
    SerialCDC.print(",");
    SerialCDC.print(lon1);
    SerialCDC.print(",");
    SerialCDC.println(ele);

    inputString = "";
    stringComplete = false;
  }

}

state_check for_upload.py

Python
read 24 hours feed chart and judge
# read 24 hours feed chart and judge
# API client.
# Author: wilson lin

import subprocess
import datetime
import json

# Set to your Adafruit IO key.
# Remember, your key is a secret,
# so make sure not to publish it when you publish this code!
ADAFRUIT_IO_KEY = 'YOUR_ADAFRUIT_IO_KEY'

# Set to your Adafruit IO username.
# (go to https://accounts.adafruit.com to find your username)
ADAFRUIT_IO_USERNAME = 'YOUR ADAFRUIT_IO_USERNAME'
FEED_NAME = 'YOUR FEED_NAME'

# # get chart data
# # can't get location data
# CHECK_HOURS = '24'
# link = 'https://io.adafruit.com/api/v2/'+ ADAFRUIT_IO_USERNAME + '/feeds/' + FEED_NAME + '/data/chart?hours=' + CHECK_HOURS
# print(link)

# get datetime 
Get_today = datetime.date.today().strftime('%Y-%m-%d')
print(Get_today)
Get_yesterday = datetime.date.today() - datetime.timedelta(1)
Get_yesterday = Get_yesterday.strftime('%Y-%m-%d')
print(Get_yesterday) 
Get_Time_hr_min = datetime.datetime.utcnow().strftime('%H:%M')
print(Get_Time_hr_min)   # 14:00:00

# # get all values in a date range
# $ curl -H "X-AIO-Key: {io_key}" "https://io.adafruit.com/api/v2/{username}/feeds/{feed_key}/data?start_time=2019-05-04T00:00Z&end_time=2019-05-05T00:00Z"
link = 'https://io.adafruit.com/api/v2/'+ ADAFRUIT_IO_USERNAME + '/feeds/' + FEED_NAME + '/data?start_time=' + Get_yesterday + 'T' + Get_Time_hr_min +'Z&end_time=' + Get_today +'T'+ Get_Time_hr_min +'Z'
print(link)

# cURL command
curl_command = 'curl -H "X-AIO-Key:'+ ADAFRUIT_IO_KEY+'" '+ link
print(curl_command)

# subprocess cURL and check output
output = subprocess.check_output(curl_command)

# decode
output = output.decode('utf-8')
print(output)

output2 = json.loads(output)
Find = False
for i in range(23):
    if int(output2[i].get('value')) < 100: # adjust for difference case
        Find = True
        print('Find failures light at: lat:'+ output2[0].get('lat') +', lon:'+output2[0].get('lon'))
        break
if not Find:
    print('Everything all right!')

Credits

Wen-Liang Lin

Wen-Liang Lin

28 projects • 34 followers
Hi, I am momososo

Comments