/*
* @portable_surveillance_system.ino
* @author Ralph Yamamoto
* @Hackster "Make it Better with Sony" Contest program entry
* @Hardware details:
* Spresense main board
* SPresense extension board
* SPresense camera
* ESP8266-01 for WiFi
* LCD Display, 1.8", 160x128, TC7735, SPI
* Pan/tilt using 2 SG90 micro servos
*
* Using Spresense GPS and Camera interfaces.
*
* January 27, 2019 Created
*
* This example code is in the public domain.
*/
/* include the libraries */
#include <SDHCI.h>
#include <stdio.h> /* for sprintf */
#include <Camera.h>
#include <GNSS.h>
#include <TFT.h>
#include <Servo.h>
/* wifi parameters */
#define SSID "removed" // Must be changed - WiFi SSID/Hostname
#define PASS "removed" // Must be changed - Encrypted password
#define APIKEY "removed" // Must be changed - API Key ThingSpeak Channel
#define APIKEY2 "removed" // Must be changed - API Key IFTTT Maker Channel
#define HOST "api.thingspeak.com" // Address of ThingSpeak API
#define HOST2 "maker.ifttt.com" // Address of IFTTT Maker Channel API
#define PORT "80" // ThingSpeak Port #
#define MONITOR true // Debug messages on serial monitor
#define WIFIMONITOR false // WiFi activity on serial monitor
#define BROADCAST true // Broadcast readings to ThingSpeak
#define POST_PERIOD 60000 // 1 minutes = 60,000ms = 60sec
#define STRING_BUFFER_SIZE 128 /* %Buffer size */
static SpGnss Gnss; /* SpGnss object */
static Servo p_servo; /* Servo object Pan*/
static Servo t_servo; /* Servo object Tilt*/
static SpNavData NavData; /* SpNavData object */
#define cs PIN_D10
#define dc PIN_D09
#define rst PIN_D08
TFT TFTscreen = TFT(cs, dc, rst); /* TFT object */
#define BAR_WIDTH 5
#define BAR_HEIGHT 80
#define BAR_DISTANCE 2
#define BAR_N_MAX 23
#define FIX_COLOR ST7735_GREEN
#define NO_FIX_COLOR ST7735_RED
#define FG_COLOR ST7735_WHITE
#define TFT_WIDTH 160
#define TFT_HEIGHT 128
#define STRLEN 60
String cmd; // Output string to the ESP8266
String passcode; // Decrypted Network password
unsigned long markTime; // Time mark for the delay timer
int cri = 0; // Index for connection
char caString[36]; // Character Array for formating String
char buff[12]; // Character Array buffer to support sprintf conversion
float xLng = 0.0; // Default Longitude 0.0
float xLat = 0.0; // Default Latitude 0.0
SDClass theSD;
int take_picture_count = 0;
int motion_count = 0;
boolean connectWifi();
static void Led_isActive(void);
static void Led_isPosfix(bool state);
static void Led_isError(bool state);
static void print_pos(SpNavData *pNavData);
void sendMotionAlert();
void motionDetectedInterrupt();
void waitTime(int milsec);
//-----------------------------------------------------------------------------
void setup() {
/* put your setup code here, to run once: */
pinMode(PIN_D03, INPUT); // configure the interrupt pin (has 1K pullup)
int error_flag = 0;
/* Attach to servo motors
Note: The pins selected must support PWM. */
p_servo.attach(PIN_D05);
t_servo.attach(PIN_D06);
/* Set the pan/tilt to 0 degrees */
p_servo.write(90); // pan
t_servo.write(90); // tilt
/* Set serial baudrate. */
if (MONITOR){
Serial.begin(115200);
while (!Serial)
{
; /* wait for serial port to connect. Needed for native USB port only */
}
}
if (MONITOR&&BROADCAST){
Serial.println("Sony Spresense ESP8266-01 posting to ThingSpeak");
Serial.println();
}
if(BROADCAST){
Serial2.begin(115200);
while(!Serial2){
; // wait for ESP8266 port to open/connect
}
}
TFTscreen.begin();
TFTscreen.setRotation(1);
TFTscreen.background(0x00);
TFTscreen.setRotation(3);
TFTscreen.background(0x00);
// write the title text to the screen
// set the font color to white
TFTscreen.stroke(255, 255, 255);
// set the font size
TFTscreen.setTextSize(2);
// write the text to the top left corner of the screen
TFTscreen.text("Portable", 20, 20);
TFTscreen.text("Security", 20, 45);
TFTscreen.text("Camera", 20, 70);
/* begin() without parameters means that
* number of buffers = 1, 30FPS, QVGA, YUV 4:2:2 format */
Serial.println("Prepare camera");
theCamera.begin(1, CAM_VIDEO_FPS_5, CAM_IMGSIZE_QVGA_H, CAM_IMGSIZE_QVGA_V,
CAM_IMAGE_PIX_FMT_YUV422);
/* Auto white balance configuration */
Serial.println("Set Auto white balance parameter");
theCamera.setAutoWhiteBalance(true);
/* Set still picture parameters */
Serial.println("Set still picture format");
theCamera.setStillPictureImageFormat(
CAM_IMGSIZE_QVGA_H,
CAM_IMGSIZE_QVGA_V,
CAM_IMAGE_PIX_FMT_JPG);
/* Wait HW initialization done. */
sleep(3);
/* Turn on all LED:Setup start. */
ledOn(PIN_LED0);
ledOn(PIN_LED1);
ledOn(PIN_LED2);
ledOn(PIN_LED3);
/* Set Debug mode to Info */
Gnss.setDebugMode(PrintInfo);
int result;
/* Activate GNSS device */
result = Gnss.begin();
if (result != 0)
{
Serial.println("Gnss begin error!!");
error_flag = 1;
}
else
{
/* Setup GNSS */
Gnss.select(QZ_L1CA); // Michibiki complement
Gnss.select(QZ_L1S); // Michibiki augmentation(Valid only in Japan)
/* Start positioning */
result = Gnss.start(COLD_START);
if (result != 0)
{
Serial.println("Gnss start error!!");
error_flag = 1;
}
else
{
Serial.println("Gnss setup OK");
}
}
/* Connect to WiFi AP. */
connectWifi();
/* Setup the ISR for the PIR sensor */
attachInterrupt (PIN_D03, sendMotionAlert, RISING);
/* Turn off all LED:Setup done. */
ledOff(PIN_LED0);
ledOff(PIN_LED1);
ledOff(PIN_LED2);
ledOff(PIN_LED3);
/* Set error LED. */
if (error_flag == 1)
{
Led_isError(true);
exit(0);
}
}
/* Callback function for live viewing */
void CamCB(CamImage img)
{
waitTime(300);
/* Check the img instance is available or not. */
if (img.isAvailable())
{
/* If you want RGB565 data, convert image data format to RGB565 */
img.convertPixFormat(CAM_IMAGE_PIX_FMT_RGB565);
/* Draw image on display */
int w = 160; //img.getWidth();
int h = 120; //img.getHeight();
int x = 0, y = 0;
int index = 0;
uint16_t *buf16;
buf16 = (uint16_t *)img.getImgBuff();
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
index = y*640 + x*2;
TFTscreen.drawPixel(x, y, buf16[index]);
}
}
theCamera.startStreaming(false, CamCB);
/* Print position information. */
print_pos(&NavData);
// waitTime(10000);
}
else
{
Serial.print("Failed to get video stream image\n");
}
}
/*
* Print position information.
*/
static void print_pos(SpNavData *pNavData)
{
char StringBuffer[STRING_BUFFER_SIZE];
uint16_t fgcolor = NO_FIX_COLOR;
/* clear the data boxes */
//TFTscreen.fill(0xc618); // hopefully gray
//TFTscreen.rect(2, 2, 135, 58);
TFTscreen.setTextSize(1);
/* print time */
snprintf(StringBuffer, STRING_BUFFER_SIZE, "%04d/%02d/%02d ", pNavData->time.year, pNavData->time.month, pNavData->time.day);
Serial.print(StringBuffer);
TFTscreen.stroke(FG_COLOR);
TFTscreen.text(StringBuffer, 10, 10);
snprintf(StringBuffer, STRING_BUFFER_SIZE, "%02d:%02d:%02d.%06d, ", pNavData->time.hour, pNavData->time.minute, pNavData->time.sec, pNavData->time.usec);
Serial.print(StringBuffer);
snprintf(StringBuffer, STRING_BUFFER_SIZE, "%02d:%02d:%02d", pNavData->time.hour, pNavData->time.minute, pNavData->time.sec);
TFTscreen.text(StringBuffer, 80, 10);
/* print satellites count */
snprintf(StringBuffer, STRING_BUFFER_SIZE, "numSat:%2d, ", pNavData->numSatellites);
Serial.print(StringBuffer);
snprintf(StringBuffer, STRING_BUFFER_SIZE, "numSat:%2d", pNavData->numSatellites);
TFTscreen.text(StringBuffer, 10, 25);
/* print position data */
if (pNavData->posFixMode == FixInvalid)
{
Serial.print("No-Fix, ");
fgcolor = NO_FIX_COLOR;
}
else
{
Serial.print("Fix, ");
fgcolor = FIX_COLOR;
}
if (pNavData->posDataExist == 0)
{
Serial.print("No Position");
TFTscreen.stroke(NO_FIX_COLOR);
TFTscreen.text("No Position", 10, 40);
}
else
{
Serial.print("Lat=");
TFTscreen.stroke(FG_COLOR);
TFTscreen.text("Lat=", 10, 40);
Serial.print(pNavData->latitude, 6);
Serial.print(", Lon=");
TFTscreen.text("Lng=", 10, 55);
Serial.print(pNavData->longitude, 6);
TFTscreen.stroke(fgcolor);
snprintf(StringBuffer, STRING_BUFFER_SIZE, "%03.4f", pNavData->latitude);
TFTscreen.text(StringBuffer, 40, 40);
snprintf(StringBuffer, STRING_BUFFER_SIZE, "%03.4f", pNavData->longitude);
TFTscreen.text(StringBuffer, 40, 55);
}
Serial.println("");
}
/*
* Print satellite information.
*/
static void print_condition(SpNavData *pNavData)
{
char StringBuffer[STRING_BUFFER_SIZE];
unsigned long cnt;
/* Print satellite count. */
snprintf(StringBuffer, STRING_BUFFER_SIZE, "numSatellites:%2d\n", pNavData->numSatellites);
Serial.print(StringBuffer);
for (cnt = 0; cnt < pNavData->numSatellites; cnt++)
{
const char *pType = "---";
SpSatelliteType sattype = pNavData->getSatelliteType(cnt);
/* Get satellite type. */
/* Keep it to three letters. */
switch (sattype)
{
case GPS:
pType = "GPS";
break;
case GLONASS:
pType = "GLN";
break;
case QZ_L1CA:
pType = "QCA";
break;
case SBAS:
pType = "SBA";
break;
case QZ_L1S:
pType = "Q1S";
break;
default:
pType = "UKN";
break;
}
/* Get print conditions. */
unsigned long Id = pNavData->getSatelliteId(cnt);
unsigned long Elv = pNavData->getSatelliteElevation(cnt);
unsigned long Azm = pNavData->getSatelliteAzimuth(cnt);
float sigLevel = pNavData->getSatelliteSignalLevel(cnt);
/* Print satellite condition. */
snprintf(StringBuffer, STRING_BUFFER_SIZE, "[%2d] Type:%s, Id:%2d, Elv:%2d, Azm:%3d, CN0:", cnt, pType, Id, Elv, Azm );
Serial.print(StringBuffer);
Serial.println(sigLevel, 6);
}
}
/*
* Main program loop
*/
void loop()
{
/* put your main code here, to run repeatedly: */
static int LastPrintMin = 0;
SpNavData *pNavData; // Pointer for NavData
/* Blink LED. */
Led_isActive();
/* Check update. */
if (Gnss.waitUpdate(-1))
{
/* Get NaviData. */
Gnss.getNavData(&NavData);
/* Set posfix LED. */
bool LedSet = (NavData.posDataExist && (NavData.posFixMode != FixInvalid));
Led_isPosfix(LedSet);
/* Print satellite information every minute. */
if (NavData.time.minute != LastPrintMin)
{
print_condition(&NavData);
LastPrintMin = NavData.time.minute;
}
/* Update data for ThingSpeak */
pNavData = &NavData;
xLng = (float) (pNavData->longitude); // recast to float
xLat = (float) (pNavData->latitude); // recast to float
Serial.println("data updated");
}
else
{
/* Not update. */
Serial.println("data not updated");
}
/* Post data to ThingSpeak */
if (BROADCAST) postReadings();
if (MONITOR) Serial.println("Start streaming");
theCamera.startStreaming(true, CamCB);
}
boolean connectWifi(){
ledOn(LED1);
if (WIFIMONITOR) Serial.println("\nAT> AT ------------------------------------------------------------");
Serial2.println("AT"); // Check: OK is returned
waitTime(500);
if (WIFIMONITOR) while (Serial2.available() > 0) Serial.write(Serial2.read());
waitTime(100);
if (WIFIMONITOR) Serial.println("\nAT> AT+RST --------------------------------------------------------");
Serial2.println("AT+RST"); // Check: OK is returned
waitTime(5500);
if (WIFIMONITOR) while (Serial2.available() > 0) Serial.write(Serial2.read());
waitTime(1000);
if (WIFIMONITOR) Serial.println("\nAT> AT+CIPMUX=0 -------------------------------------------------");
Serial2.println("AT+CIPMUX=0"); // Single connection mode: OK is returned
waitTime(500);
if (WIFIMONITOR) while (Serial2.available() > 0) Serial.write(Serial2.read());
waitTime(100);
if (WIFIMONITOR) Serial.println("\nAT> AT+CWMODE=1 ---------------------------------------------------");
Serial2.println("AT+CWMODE=1"); // Client=1: OK is returned
waitTime(500);
if (WIFIMONITOR) while (Serial2.available() > 0) Serial.write(Serial2.read());
waitTime(100);
ledOn(LED2);
cmd="AT+CWJAP=\"";cmd+=SSID;cmd+="\",\"";cmd+=PASS;cmd+="\"";
if (WIFIMONITOR){ Serial.print("\nAT> ");Serial.print(cmd); Serial.println(" ---------------------------------------");}
for (cri=0; cri <= 3; cri++){
Serial2.println(cmd); // Join Access Point: OK is returned after about 3-4 seconds
Serial2.flush();
waitTime(6000);
if (Serial2.find((char *)"OK")){
if (MONITOR){
if (WIFIMONITOR) Serial.println(cmd);
Serial.print("Network Connected! ("); Serial.print(cri); Serial.println(")");
}
cri=5;
break;
}
}
if (cri==3){
if (MONITOR){
while (Serial2.available() > 0) Serial.write(Serial2.read());
Serial.println("AT+CWJAP failed...");
}
}
if (WIFIMONITOR){
while (Serial2.available() > 0) Serial.write(Serial2.read());
Serial.write("AT+CWJAP=SSID"); // Do not expose decypted password
}
waitTime(100);
if (WIFIMONITOR) Serial.println("\nAT> AT+CIFSR ------------------------------------------------------");
Serial2.println("AT+CIFSR"); // Check Connection status
Serial2.flush();
waitTime(2000);
if (WIFIMONITOR){
while (Serial2.available() > 0) Serial.write(Serial2.read());
Serial.println();
}
}
//---------------------------------------------------------------
void postReadings(){
cmd = "AT+CIPSTART=\"TCP\",\"";
cmd += HOST;
cmd += "\",80";
ledOn(LED3);
if (WIFIMONITOR) Serial.println("\nAT> AT+CISTART ----------------------------------------------------");
for (cri=0; cri <= 3; cri++){
Serial2.println(cmd); // Conenct to ThingSpeak: CONNECT is returned after about 1-2 seconds
Serial2.flush();
waitTime(4000);
if (Serial2.find((char *)"CONNECT")){
if (MONITOR){
if (WIFIMONITOR) Serial.println(cmd);
Serial.print("Thingspeak Connected! ("); Serial.print(cri); Serial.println(")");
}
cri=5;
break;
}
}
if (cri==3){
if (MONITOR){
while (Serial2.available() > 0) Serial.write(Serial2.read());
Serial.println("Thingspeak Connection failed...");
}
}
cmd = "GET /update?api_key="; cmd += APIKEY;
cmd += "&field1="; sprintf(buff,"%.6f",xLat); cmd += buff;
cmd += "&field2="; sprintf(buff,"%.6f",xLng); cmd += buff;
cmd += "\r\n";
if (WIFIMONITOR){
Serial.print("\nAT> AT+CIPSEND=");
Serial.print(cmd.length());
Serial.println(" ------------------------------------------------");
}
Serial2.print("AT+CIPSEND=");
Serial2.println(cmd.length()); // Send length of IP string: OK is returned
Serial2.flush();
waitTime(2000);
if (WIFIMONITOR) while (Serial2.available() > 0) Serial.write(Serial2.read());
if (WIFIMONITOR){
Serial.println("\n> GET -------------------------------------------------------------");
Serial.print("> "); Serial.println(cmd);
}
Serial2.println(cmd); // Send Get/Post command: SEND OK and +IPD,1:5CLOSED are returned
Serial2.flush();
waitTime(3000);
if (WIFIMONITOR) while (Serial2.available() > 0) Serial.write(Serial2.read());
}
void sendMotionAlert(){
cmd = "AT+CIPSTART=\"TCP\",\"";
cmd += HOST2;
cmd += "\",80";
ledOn(LED3);
if (WIFIMONITOR) Serial.println("\nAT> AT+CISTART ----------------------------------------------------");
for (cri=0; cri <= 3; cri++){
Serial2.println(cmd); // Conenct to IFTTT Maker: CONNECT is returned after about 1-2 seconds
Serial2.flush();
waitTime(4000);
if (Serial2.find((char *)"CONNECT")){
if (MONITOR){
if (WIFIMONITOR) Serial.println(cmd);
Serial.print("IFTTT Maker Connected! ("); Serial.print(cri); Serial.println(")");
}
cri=5;
break;
}
}
if (cri==3){
if (WIFIMONITOR){
while (Serial2.available() > 0) Serial.write(Serial2.read());
Serial.println("IFTTT Maker Connection failed...");
}
}
cmd = "GET /trigger/motion_detected_spresense/with/key/"; cmd += APIKEY2;
cmd += "\r\n\r\n";
if (WIFIMONITOR){
Serial.print("\nAT> AT+CIPSEND=");
Serial.print(cmd.length());
Serial.println(" ------------------------------------------------");
}
Serial2.print("AT+CIPSEND=");
Serial2.println(cmd.length()); // Send length of IP string: OK is returned
Serial2.flush();
waitTime(2000);
if (WIFIMONITOR) while (Serial2.available() > 0) Serial.write(Serial2.read());
if (WIFIMONITOR){
Serial.println("\n> GET -------------------------------------------------------------");
Serial.print("> "); Serial.println(cmd);
}
Serial2.println(cmd); // Send Get/Post command: SEND OK and +IPD,1:5CLOSED are returned
Serial2.flush();
waitTime(3000);
if (WIFIMONITOR) while (Serial2.available() > 0) Serial.write(Serial2.read());
}
//------------------------------------------------------------------------
// Supplement to delay() fucntion as delay() does not pause all actions and is asynchronous.
//------------------------------------------------------------------------
void waitTime(int milsec){
markTime = millis();
while (millis()-markTime < milsec){
}
}
//------------------------------------------------------------------------
/*
* LED helper functions
* LED0 CPU Active
* LED1 PosFix
* LED2 Error
*/
static void Led_isActive(void)
{
static int state = 1;
if (state == 1)
{
ledOn(PIN_LED0);
state = 0;
}
else
{
ledOff(PIN_LED0);
state = 1;
}
}
static void Led_isPosfix(bool state)
{
if (state)
{
ledOn(PIN_LED1);
}
else
{
ledOff(PIN_LED1);
}
}
static void Led_isError(bool state)
{
if (state)
{
ledOn(PIN_LED3);
}
else
{
ledOff(PIN_LED3);
}
}
void motionDetectedInterrupt() {
// Send PIR Alert.
Serial.println("Send Motion Alert");
sendMotionAlert();
Serial.print("motion_count = ");
Serial.println(motion_count);
motion_count++;
}
Comments