How to turn on LED that's attached to an arduino via BLE from ios app? - ios

Here is the scenario. I have an esp32, 2 led's and a ios example app I found online here. Currently If I press a button on my esp32 it notifies the ios app to display "1", if pressed again it displays "0". This works perfectly.
The tricky part is that this ios app allows me to send a write command to the esp32. I'd like to make it so if '1' is sent LED A turns ON and LED B turns OFF, then LED A OFF and LED B ON when 0 is sent. I am unable to do this though. Try as I might I can't figure out where in the chain of this project something is wrong. Maybe the code on the esp32 or maybe the app i'm unsure.
Here is my arduino code. (There is more to the code not mentioned, I actually have 4 led's but I only want to turn on 2 certain ones when a write command is sent).
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;
boolean oldState = LOW;
uint32_t value = 0;
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++) {
Serial.print(rxValue[i]);
}
Serial.println();
if (rxValue.find("1") != -1) {
digitalWrite(13, HIGH);
digitalWrite(27, LOW);
}
else if (rxValue.find("0") != -1) {
digitalWrite(13, LOW);
digitalWrite(27, HIGH);
}
}
}
};
const int bt1 = 14;
boolean bt1g = true;
int bt1t = 0;
void setup() {
pinMode(13, OUTPUT);
pinMode(15, OUTPUT);
pinMode(33, OUTPUT);
pinMode(27, OUTPUT);
pinMode(bt1, INPUT_PULLUP);
Serial.begin(9600);
BLEDevice::init("ESP32");
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY
);
pCharacteristic->addDescriptor(new BLE2902());
pService->start();
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(false);
pAdvertising->setMinPreferred(0x0);
BLEDevice::startAdvertising();
Serial.println("Waiting a client connection to notify...");
}
void loop()
{
if (bt1g) {
if (digitalRead(bt1) == LOW ) {
bt1t = (bt1t + 1) % 2;
Serial.println(bt1t);
bt1g = false;
}
}
if (!bt1g) {
if (digitalRead(bt1) == HIGH) {
bt1g = true;
}
}
if (bt1t == 0) {
digitalWrite(15, LOW);
digitalWrite(33, HIGH);
}
}
boolean newState = digitalRead(15);
if (deviceConnected) {
if (newState != oldState) {
if (newState == LOW) {
pCharacteristic->setValue("1");
}
else {
pCharacteristic->setValue("0");
}
pCharacteristic->notify();
};
oldState = newState;
}
delay(50);
}
It looks like the entire code for the ios app is too long to submit to this post so here is the github
I'm really unsure and stuck in a rut. Any help is appreciated!

Could it be you are not discovering the correct characteristics? It looks like you only have one service and one characteristic.

Related

How to send a chunk of data using shlib(nghttp2) in esp32?

I want to use HTTP2 to POST data continuously. As I found, the only feasible solution is to use shlib. I can implement it and use it. But there were two problems that I faced:
1- shlib does not let us send a data bigger than 16KB theoretically. Here, the solution that I found was to feed the buffer couple of times without calling NGHTTP2_DATA_FLAG_EOF. But, the main problem is that we cannot return the size of the buffer which although is defined as int, but does not support lengths more than 16K.
2- The fault rate of sending data more than about 3 to 4K goes exponentially high as in these situations, just a few of packets are able to be sent correctly.
Any suggestion?
Thanks
I did all my bests to make sure that the resources don't interfere with each other. Here is my code:
#include <Arduino.h>
#include <WiFiClientSecure.h>
#include "esp_camera.h"
extern "C"
{
#include "sh2lib.h"
}
#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif
// CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
const char* ssid = "NETWORK"; // your network SSID (name of wifi network)
const char* password = "PASSWORD"; // your network password
bool request_finished = false;
String head = "--JPEG_IMAGE\r\nContent-Disposition: form-data; name=\"imageFile\"; filename=\"esp32-cam.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n";
String tail = "\r\n--JPEG_IMAGE--\r\n";
char data_to_post[16000];
uint32_t totalLen;
camera_config_t config;
struct sh2lib_handle hd;
bool is_captured;
bool is_posted;
uint16_t safety_counter;
void setup()
{
// put your setup code here, to run once:
Serial.begin(115200);
delay(100);
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
// attempt to connect to Wifi network:
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
// wait 1 second for re-trying
delay(1000);
}
Serial.print("\n");
Serial.print(F("Connected to: "));
Serial.println(ssid);
// Etablishing Connection
Serial.println(F("Establishing Connection... "));
if (sh2lib_connect(&hd, "My_Server") != ESP_OK)
{
Serial.println("Error connecting to HTTP2 server");
//vTaskDelete(NULL);
}
Serial.println(F("Connected to the webserver"));
delay(1000);
// Configuring the Cam
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
// init with high specs to pre-allocate larger buffers
if(psramFound())
{
config.frame_size = FRAMESIZE_VGA;// FRAMESIZE_QVGA
config.jpeg_quality = 10; //0-63 lower number means higher quality
config.fb_count = 2;
}
else
{
config.frame_size = FRAMESIZE_CIF;
config.jpeg_quality = 12; //0-63 lower number means higher quality
config.fb_count = 1;
}
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK)
{
Serial.printf("Camera init failed with error 0x%x", err);
delay(1000);
ESP.restart();
}
// This task handles the POST requests
xTaskCreatePinnedToCore(
task_http2
, "http2_task"
, (1024 * 24) // Stack size
, NULL
, 3 // Priority
, NULL
, ARDUINO_RUNNING_CORE);
Serial.println(F("Task Called"));
}
void loop()
{
// To prohibit the interference between resources, I used main loop to capture the Images
// Check if the posting has been finished
if (is_posted)
{
Serial.println(F("Call to Capture"));
camera_fb_t * fb = NULL;
fb = esp_camera_fb_get();
if(!fb)
{
Serial.println("Camera capture failed");
delay(1000);
ESP.restart();
}
// to check if the size is not bigger than 16K
uint32_t imageLen = fb->len;
if(imageLen<16000)
{
// Creating the body of the post
uint32_t extraLen = tail.length()+head.length();
totalLen = extraLen + imageLen;
uint8_t *fbBuf = fb->buf;
const char* head_char = head.c_str();
const char* tail_char = tail.c_str();
uint32_t totalLen_copy = totalLen;
char alpha[totalLen];
std::copy(head_char,head_char+head.length(), data_to_post);
std::copy(fbBuf,fbBuf+imageLen , data_to_post+head.length());
std::copy(tail_char,tail_char+ tail.length(), data_to_post+head.length()+imageLen);
esp_camera_fb_return(fb);
Serial.println(F("Camera captured"));
delay(100);
safety_counter++;
// Stopping capturing until posting is finished
is_captured = true;
is_posted = false;
}
}
delay(100);
}
int handle_get_response(struct sh2lib_handle *handle, const char *data, size_t len, int flags)
{
if (len > 0)
{
Serial.printf("%.*s\n", len, data);
}
if (flags == DATA_RECV_RST_STREAM)
{
Serial.println("STREAM CLOSED");
}
return 0;
}
int handle_post_response(struct sh2lib_handle *handle, const char *data, size_t len, int flags)
{
if (len > 0) {
Serial.printf("%.*s\n", len, data);
// decreasing the counter to prevent fault loop
safety_counter--;
}
//Serial.print(F("Safety_Counter in Response: ")); Serial.println(safety_counter);
if (flags == DATA_RECV_RST_STREAM) {
request_finished = true;
Serial.println("STREAM CLOSED");
}
return 0;
}
int send_post_data(struct sh2lib_handle *handle, char *buf, size_t length, uint32_t *data_flags)
{
// To check the body of the post
/*
Serial.println("Post Buffer");
for(int i;i<totalLen;i++)
Serial.print(data_to_post[i]);
Serial.println("Post Buffer End");
*/
if (totalLen < length)
{
memcpy(buf, data_to_post, totalLen);
}
else
{
Serial.println("Cannot write to buffer");
//copylen = 0;
}
(*data_flags) |= NGHTTP2_DATA_FLAG_EOF;
return totalLen;
}
void task_http2(void *args)
{
Serial.println(F("Task Runs"));
// Start capturing
is_posted = true;
int counter = 0;
for(;;)
{
// if capturing finished:
if(is_captured)
{
// after each five unsuccessful posts, reestablish the connection
Serial.print(F("Safety_Counter is: ")); Serial.println(safety_counter);
if(safety_counter>5)
{
is_posted = false;
vTaskDelay(100);
counter = 0;
safety_counter = 0;
sh2lib_free(&hd);
vTaskDelay(100);
Serial.println(F("Safety Counter Occured ... "));
if (sh2lib_connect(&hd, "My_Server") != ESP_OK)
{
Serial.println("Error connecting to HTTP2 server");
//vTaskDelete(NULL);
}
Serial.println(F("Connected to the webserver"));
vTaskDelay(1000);
// Preparing capturing again
is_posted = true;
is_captured = false;
continue;
}
char len[20];
sprintf(len, "%d",totalLen); //length_of_body);
Serial.print("the length is: ");
Serial.println(len);
const nghttp2_nv nva[] = { SH2LIB_MAKE_NV(":method", "POST"),
SH2LIB_MAKE_NV(":scheme", "https"),
SH2LIB_MAKE_NV(":authority", hd.hostname),
SH2LIB_MAKE_NV(":path", "/mvp/upload_image"),
SH2LIB_MAKE_NV("Content-Length", len),
SH2LIB_MAKE_NV("Content-Type", "multipart/form-data; boundary=JPEG_IMAGE")
};
sh2lib_do_putpost_with_nv(&hd, nva, sizeof(nva) / sizeof(nva[0]), send_post_data, handle_post_response);
while (1)
{
if (sh2lib_execute(&hd) != ESP_OK)
{
Serial.println("Error in execute");
break;
}
if (request_finished)
{
// a general counter to reestablish the connection
counter++;
break;
}
//vTaskDelay(1000);
}
}
// General counter
if(counter>30)
{
counter = 0;
sh2lib_free(&hd);
vTaskDelay(100);
Serial.println(F("Establishing Connection... "));
if (sh2lib_connect(&hd, "My_Server") != ESP_OK)
{
Serial.println("Error connecting to HTTP2 server");
//vTaskDelete(NULL);
}
Serial.println(F("Connected to the webserver"));
}
is_captured = false;
is_posted = true;
Serial.println("Sending finished");
vTaskDelay(1000);
}
}

ESP8266 WeMos D1 using deepsleep drains too much battery

I've developed a fingerprint sensor using NodeMCU D1 mini powered by a 1000mah battery.
Everything seems working correctly except for battery energy consumption.
I have read several topic where user says that using deepsleep fuction on NodeMCU 1000mah battery should last more than 3 month but mine doesn't reach 2 days.
This is my circuit schematic
I also report here my code snipped that I'm currently using. The circuit should wake up from deepsleep when the button is pressed and start reading the fingerprint sensor. If it detect a valid fingerprint, a message is sent to MQTT broker.
#include <Adafruit_Fingerprint.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
const char* _ssid = "ZZZXXXYYY";
const char* _password = "pass";
const char* mqttServer = "IPADDRESS";
const int mqttPort = 1883;
const char* mqttUser = "USER";
const char* mqttPassword = "PASS";
long initialMillis = 0;
unsigned int raw=0;
// On Leonardo/Micro or others with hardware serial, use those! #0 is green wire, #1 is white
// uncomment this line:
//#define mySerial Serial
// For UNO and others without hardware serial, we must use software serial...
// pin #2 is IN from sensor (GREEN wire)
// pin #3 is OUT from arduino (WHITE wire)
// comment these two lines if using hardware serial
SoftwareSerial mySerial(4, 5);
WiFiClient espClient;
PubSubClient client(espClient);
Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);
void setup()
{
Serial.begin(9600);
pinMode(A0, INPUT);
// Connect to Fingerprint. Set the data rate for the sensor serial port
finger.begin(57600);
delay(5);
if (finger.verifyPassword()) {
Serial.println("Found fingerprint sensor!");
} else {
Serial.println("Did not find fingerprint sensor :(");
ESP.deepSleep(10 * 1000000);
}
finger.getTemplateCount();
// Connect to WIFI
WiFi.mode(WIFI_STA);
WiFi.begin(_ssid, _password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
// Connect to MQTT
client.setServer(mqttServer, mqttPort);
while (!client.connected()) {
Serial.println("Connecting to MQTT...");
if (client.connect("ESPFingerprint", mqttUser, mqttPassword )) {
Serial.println("Connected to MQTT server");
} else {
Serial.print("failed with state ");
Serial.print(client.state());
delay(2000);
}
}
// Calculate battery percentage
raw = analogRead(A0);
String bLevel = "{\"Battery\":" + String(raw) + "}";
Serial.print("Battery: ");
Serial.print(raw);
Serial.print(" -> ");
Serial.println(bLevel);
initialMillis = millis();
client.publish("tele/fingerprint/LWT", "Online");
client.publish("tele/fingerprint/STATE", (char*)bLevel.c_str(), true);
Serial.print("MQTT subscribed: ");
Serial.println(WiFi.localIP());
}
void loop()
{
unsigned long currentMillis = millis();
int fid = getFingerprintIDez();
if(fid != -1) {
String fpIdstr = String(fid);
client.publish("cmnd/fingerprint/RESULT", (char*)fpIdstr.c_str());
Serial.println("Fingerprint correct. Going to sleep.");
client.publish("tele/fingerprint/LWT", "Offline");
// trigger disconnection from MQTT broker to correctly send the message before going to sleep
client.disconnect();
espClient.flush();
// wait until connection is closed completely
while(client.state() != -1){
delay(10);
}
ESP.deepSleep(0);
}
else if(currentMillis - initialMillis >= 15000){
Serial.println("Timeout expired. Going to sleep.");
client.publish("tele/fingerprint/LWT", "Offline");
ESP.deepSleep(0);
}
delay(50); //don't ned to run this at full speed.
}
uint8_t getFingerprintID() {
uint8_t p = finger.getImage();
switch (p) {
case FINGERPRINT_OK:
Serial.println("Image taken");
break;
case FINGERPRINT_NOFINGER:
Serial.println("No finger detected");
return p;
case FINGERPRINT_PACKETRECIEVEERR:
Serial.println("Communication error");
return p;
case FINGERPRINT_IMAGEFAIL:
Serial.println("Imaging error");
return p;
default:
Serial.println("Unknown error");
return p;
}
// OK success!
p = finger.image2Tz();
switch (p) {
case FINGERPRINT_OK:
Serial.println("Image converted");
break;
case FINGERPRINT_IMAGEMESS:
Serial.println("Image too messy");
return p;
case FINGERPRINT_PACKETRECIEVEERR:
Serial.println("Communication error");
return p;
case FINGERPRINT_FEATUREFAIL:
Serial.println("Could not find fingerprint features");
return p;
case FINGERPRINT_INVALIDIMAGE:
Serial.println("Could not find fingerprint features");
return p;
default:
Serial.println("Unknown error");
return p;
}
// OK converted!
p = finger.fingerFastSearch();
if (p == FINGERPRINT_OK) {
Serial.println("Found a print match!");
} else if (p == FINGERPRINT_PACKETRECIEVEERR) {
Serial.println("Communication error");
return p;
} else if (p == FINGERPRINT_NOTFOUND) {
Serial.println("Did not find a match");
return p;
} else {
Serial.println("Unknown error");
return p;
}
// found a match!
Serial.print("Found ID #"); Serial.print(finger.fingerID);
Serial.print(" with confidence of "); Serial.println(finger.confidence);
return finger.fingerID;
}
// returns -1 if failed, otherwise returns ID #
int getFingerprintIDez() {
uint8_t p = finger.getImage();
if (p != FINGERPRINT_OK) return -1;
p = finger.image2Tz();
if (p != FINGERPRINT_OK) return -1;
p = finger.fingerFastSearch();
if (p != FINGERPRINT_OK) return -1;
// found a match!
Serial.print("Found ID #"); Serial.print(finger.fingerID);
Serial.print(" with confidence of "); Serial.println(finger.confidence);
return finger.fingerID;
}
Can somebody let me know if there is something wrong in my code or circuit?

How to connect into Action Cable websocket from Arduino?

I built an app in Python Flask which controls the LED light on an Arduino through broadcasting the color selected in a form to all members of the websocket channel. I am now rebuilding in Rails and trying to determine how my Arduino can specify which channel it would like to join. I've already begun a connection to the WebSocket and seem to be getting the following back from Rails: [WSc] Received text: {"type":"ping","message":1544679171}.
Now I just need to determine how I can send in a request to specifically stream from the ArduinoChannel, but I'm not sure how to go about it. I've tried adding parameters to my webSocket.begin, but that doesn't seem to have any affect.
Below is my Arduino code for reference:
#include <ESP8266WiFi.h>
#include <WebSocketsClient.h>
#include <ArduinoJson.h>
#include <EEPROM.h>
// Initialize pins
int redpin = D0;
int greenpin = D2;
int bluepin = D4;
//// Connecting to the internet
const char* ssid = "**************";
const char* password = "******";
// Setting up the websocket client
WebSocketsClient webSocket;
// Set up the WiFi client;
WiFiClient client;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(redpin, OUTPUT);
pinMode(bluepin, OUTPUT);
pinMode(greenpin, OUTPUT);
delay(10);
WiFi.begin(ssid, password);
while(WiFi.status()!= WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println("");
Serial.print("IP Address: ");
Serial.print(WiFi.localIP() + "\n");
Serial.print(WiFi.macAddress() + "\n");
// Initializing the WS2812B communication
setRgb(255,80,90);
// Initializing the websocket connection
webSocket.begin("192.168.1.93",3000, "/cable" );
// webSocket.sendTXT('{"command":"subscribe","identifier":"{\"channel\":\"ArduinoChannel\"}"', 0);
webSocket.onEvent(webSocketEvent);
webSocket.setReconnectInterval(5);
}
void loop() {
// put your main code here, to run repeatedly:
webSocket.loop();
}
void webSocketEvent(WStype_t type, uint8_t *payload, size_t length) {
switch(type) {
Serial.write(type);
case WStype_DISCONNECTED:
Serial.printf("[WSc] Disconnected!\n");
break;
case WStype_CONNECTED:
Serial.printf("[WSc] Connected to url: %s\n", payload);
break;
case WStype_TEXT:
Serial.printf("[WSc] Received text: %s\n", payload);
DynamicJsonBuffer jBuffer;
JsonObject &root = jBuffer.parseObject(payload);
setRgb(root["r"],root["g"],root["b"]);
break;
}
}
void setRgb(uint8_t r, uint8_t g, uint8_t b) {
analogWrite(redpin, r);
analogWrite(bluepin, b);
analogWrite(greenpin, g);
delay(10);
}
TL;DR:
how I can send in a request to specifically stream from the ArduinoChannel
To receive streams from ArduinoChannel, you'll need to "subscribe" by sending through Websocket connection the following the String data from Arduino-client:
"{\"command\":\"subscribe\",\"identifier\":\"{\\\"channel\\\":\\\"ArduinoChannel\\\"}\"}"
... which is almost the same as your commented out sendTXT code, but that probably you were just incorrectly "escaping" the double quotes.
References:
I traced from the JS-client version of ActionCable here
App.cable.subscriptions.create('ArduinoChannel')
Subscriptions.prototype.create = function create(channelName, mixin) {
var channel = channelName;
var params = (typeof channel === "undefined" ? "undefined" : _typeof(channel)) === "object" ? channel : {
channel: channel
};
// params = { channel: "ArduinoChannel" }
var subscription = new Subscription(this.consumer, params, mixin);
return this.add(subscription);
};
function Subscription(consumer) {
var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var mixin = arguments[2];
classCallCheck(this, Subscription);
this.consumer = consumer;
this.identifier = JSON.stringify(params);
extend(this, mixin);
}
Subscriptions.prototype.add = function add(subscription) {
this.subscriptions.push(subscription);
this.consumer.ensureActiveConnection();
this.notify(subscription, "initialized");
this.sendCommand(subscription, "subscribe");
return subscription;
};
Subscriptions.prototype.sendCommand = function sendCommand(subscription, command) {
var identifier = subscription.identifier;
// command = "subscribe"; identifier = JSON.stringify(params) = '{"channel":"ArduinoChannel"}';
return this.consumer.send({
command: command,
identifier: identifier
});
};
Consumer.prototype.send = function send(data) {
// data = { command: 'subscribe', identifier: '{"channel":"ArduinoChannel"}' }
return this.connection.send(data);
};
Connection.prototype.send = function send(data) {
if (this.isOpen()) {
// JSON.stringify(data) = '{"command":"subscribe","identifier":"{\"channel\":\"ArduinoChannel\"}"}'
this.webSocket.send(JSON.stringify(data));
return true;
} else {
return false;
}
};

Arduino's serial communication with gsm board

I am trying to write a program where arduino receives text from the gsm module.But my program is able to read the first text and perform a duty,but i want it to receive multiple texts and perform individual tasks for each respective texts?Any help will be great.Thank You.
#include <SoftwareSerial.h>
SoftwareSerial gsm(2, 3);
String inString[64]; // string to hold input coming from device
String read;
int count = 0;
boolean verifyingDone = false; // flags to determine the action completed and to perform next action
boolean regist = false;
boolean registercomplete = false;
boolean location = false;
void setup()
{
// put your setup code here, to run once:
Serial.begin(9600);
gsm.begin(4800);
delay(100);
gsm.print("ate0\r"); // removes the echo from the device
delay(100);
gsm.print("at+cnmi=1,2,0,0,0\r"); // to receive a text
Serial.print("The Device has been Intiated");
}
void loop() {
if (gsm.available())
{
while (gsm.available())
{
read = gsm.readString();
verifyNum(); // verifying the number
/* verifyingDone=true;
if(verifyingDone){
delay(1000);
gsm.print("at+cgpsinfo\r");
delay(1000);
checkGps();
verifyingDone=false;
*/
reading1: inString[count++] = read;
Serial.print(String(read));
if (count == 64) {
break;
}
}
delay(200);
count = 0;
}
}
void clearBufferArray()
{
for (int i = 0; i < count; i++)
{
inString[i] = "";
}
}
void verifyNum() {
if (read.startsWith("\r\n+CMT: ")) { // checking the incoming text and verifying the pre-defined number
int index1 = read.indexOf('"');
int index2 = read.indexOf('"', index1 + 1);
String Number = read.substring(index1 + 2, index2);
char floatbuf[100]; // make this at least big enough for the whole string
Number.toCharArray(floatbuf, 100);
int number = atoi(floatbuf);
//Serial.println(number);
delay(1000);
if (strcmp(number, 24190) == 0)
{
Serial.println("The Sending number is " + Number);
Serial.println("This is the registered number");
regist = true;
if (regist) {
gsm.print("AT+CMGS=\"0434519166\"\r"); // Sending registeration confirmation via sms
delay(100);
gsm.print("Success this mobile number has been registered .\r");
gsm.print("\r");
delay(100);
gsm.println((char)26);
delay(10000);
registercomplete = true;
if (regist == true && registercomplete == true) { //after complete registeration ,checking the gps and sending the co-ordinates
checkGps();
delay(500);
}
}
else {
gsm.print("AT+CMGSO=\"0434519166\" \,\"Someone tried to access your device\"\r"); // When not a registered number
}
}
}
}
void checkGps()
{
Serial.print("Gps Search has started");
delay(10000);//big delay to complete previous process //Not able to do this process completely------>Coz not able to re-read the string obtained from the first read..have to find an alternate to read incoming signals efficiently and re-using it
clearBufferArray();
delay(1000);
gsm.write("at+cgpsinfo\r");
delay(10000);
Serial.println();
Serial.println();
Serial.print("Locating.....Wait for a moment");
/*int spacePosition = read.indexOf(':');
if (read.charAt(spacePosition + 1) == ',' && regist==true )*/
if (read.startsWith("\r\n+CGPINFO:,,,"))
{
Serial.println("GPS signal not found.Go outside"); //
gsm.print("AT+CMGS=\"0434519166\"\r"); // Sending location as sms
delay(100);
gsm.print("GPS signal not found.Go outside ");
gsm.print("\r");
delay(100);
gsm.println((char)26);
delay(1000);
regist = false;
}
else
{
Serial.println("Signal found");
gsm.print("AT+CMGS=\"0434519166\"\r"); //Confirming signal found and sending location----->location finding programs can be obtained from previouses sketches
delay(100);
gsm.print("GPS found.Location will be sent soon ");
gsm.print("\r");
delay(100);
gsm.println((char)26);
delay(1000);
}
}
Thank You,Above code is justa tryout ,any help is welcome!

How did TIdTCPServer multicast to ALL Clients in A 60Hz timer?

I am a newbie working with Indy. This is my first time posting a question here.
My project has to send data to all clients at 60Hz. I am using TIdTCPServer for this, and to monitor keep-alives. My tool is very old, running on WinXP, using C++Builder 6 and Indy 8. There is a potential timeout issue, does anyone have a good thought how to handle it?
Here is my code:
Server Side
typedef struct
{
AnsiString PeerIP; //{ Cleint IP address }
AnsiString HostName; //{ Hostname }
int Id; // {Cleint ID}
} TClient;
// This is Multimedia timer callback function, on 60Hz
void CALLBACK mmTimerProc(UINT wTimerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
DWORD T1, T2;
TfmMain *pMain = (TfmMain *)dwUser;
int Index;
double dT;
TClient *pClient;
if (pMain->IsClosing) return;
if (pMain->Shutdown)
{
return;
}
pMain->UpdateServer1Data();
TList *pList = pMain->IdTCPServer1->Threads->LockList();
try
{
for(int X = 0; X < pList->Count; X++)
{
if (!pMain->IsClosing)
{
TIdPeerThread *AThread = (TIdPeerThread *)pList->Items[X];
if(AThread != NULL)
{
pClient = (TClient *)AThread->Data;
try
{
if(!AThread->Connection->ClosedGracefully)
{
// Send data to ALL Clients
AThread->Connection->WriteBuffer(&pMain->Data2Client, sizeof(pMain->Data2Client), true);
}
}
catch(Exception &E)
{
if(!AThread->Stopped)
{
AThread->Stop();
AThread->Connection->Disconnect();
}
}
}
}
}
}
__finally
{
pMain->IdTCPServer1->Threads->UnlockList();
}
// Shutdown computer or close application
if(pMain->SimIos.Status.iSimStatus == 11)
{
pMain->Shutdown = true;
pMain->CloseApp();
}
}
void __fastcall TfmMain::IdTCPServer1Connect(TIdPeerThread *AThread)
{
TClient *pClient = NULL;
AnsiString ABuffer, text;
AnsiString PeerIP = AThread->Connection->Binding->PeerIP;
TDateTime TimeConnected = Now();
ABuffer = AThread->Connection->ReadLn();
if((ABuffer.Pos("TT") == 0) && (ABuffer.Pos("IG") == 0) && (ABuffer.Pos("RR") == 0))
{
text = AnsiString().sprintf("1>>> Unknown(%s) on %s connected illegal!...",
PeerIP, DateTimeToStr(TimeConnected));
WriteMsg(text);
AThread->Connection->Disconnect();
return;
}
if(ABuffer.Pos("IG") != 0)
{
pClient = new TClient;
pClient->PeerIP = PeerIP;
pClient->HostName = Clients[eIG];
pClient->Id = eIG;
AThread->Data = (TObject *)pClient;
AThread->FreeOnTerminate = true;
// Report client is on line
}
text = AnsiString().sprintf("1>>>%s(%s) on %s on line!...",
pClient->HostName, PeerIP, DateTimeToStr(TimeConnected));
WriteMsg(text);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::IdTCPServer1Disconnect(TIdPeerThread *AThread)
{
TClient *pClient = NULL;
AnsiString Msg;
if (IsClosing) return;
pClient = (TClient *)AThread->Data;
if(pClient->Id == 1)
{
// Report client is off line
Msg = AnsiString().sprintf("1>>>%s(%s) on %s off line...",
pClient->HostName, pClient->PeerIP, DateTimeToStr(Now()));
WriteMsg(Msg);
}
delete pClient;
AThread->Data = NULL;
AThread->Terminate();
try
{
IdTCPServer1->Threads->LockList()->Remove(AThread);
}
__finally
{
IdTCPServer1->Threads->UnlockList();
}
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::IdTCPServer1Execute(TIdPeerThread *AThread)
{
TClient *pClient;
if (!AThread->Terminated && !IsClosing)
{
pClient = (TClient *)AThread->Data;
if((pClient != NULL) && (pClient->Id != 0))
{
try
{
if(pClient->Id == 1)
{
// Report client still alive
}
}
catch(Exception &E)
{
if (!IsClosing)
{
if(!AThread->Stopped)
{
AThread->Stop();
AThread->Connection->Disconnect();
}
}
}
}
}
}
Client side
void __fastcall TSocketThread::Execute()
{
unsigned long ulCheckSum;
SIM_SVR1_ACK_STRUCT Ack2Svr;
SIM_SVR_DATA DataFromSvr;
int Counter;
memset(&DataFromSvr, 0, sizeof(DataFromSvr));
memset(&Ack2Svr, 0, sizeof(Ack2Svr));
Counter = 0;
// fetch and process commands until the connection or thread is terminated
while (!this->Terminated && FSocket->Connected())
{
try
{
// recieve data from server
FSocket->ReadBuffer(&DataFromSvr, sizeof(DataFromSvr));
// check CRC
ulCheckSum = CRC_32((unsigned char*)&DataFromSvr.SimData, sizeof(DataFromSvr.SimData));
if (ulCheckSum == DataFromSvr.uiCheckSum)
{
FSmIpcUtil->Writeto(&DataFromSvr.SimData, DATA_OFFSET, sizeof(DataFromSvr.SimData));
}
else
{
// counter to record error
Synchronize(UpdateCaption);
}
// read return from local SM
FSmIpcUtil->Readfrom(&Ack2Svr, ACK_OFFSET, sizeof(Ack2Svr));
FSocket->WriteBuffer(&Ack2Svr, sizeof(Ack2Svr));
if (DataFromSvr.SimData.SimIgTgt.Acdata.iSimStatus == 11)
{
Terminate();
FSocket->Disconnect();
PostMessage(Application->Handle, WM_SHUTDOWN, 0, 0);
Sleep(500);
}
}
catch (EIdException& E)
{
this->Terminate();
FSocket->Disconnect();
}
}
}
There are several issues with your code.
A multimedia timer callback is very restricted in what it is allowed to do:
Applications should not call any system-defined functions from inside a callback function, except for PostMessage, timeGetSystemTime, timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg, midiOutLongMsg, and OutputDebugString.
If transmission speed is important, don't have the timer callback do the broadcasting at all. Save the data somewhere safe, and then have each TIdTCPServer thread grab the latest data on its own time. This also keeps each connection thread isolated so one connection cannot affect any other connection if problems occur.
DO NOT set the TIdPeerThread::FreeOnTerminate to true, DO NOT call TIdPeerThread::Stop(), DO NOT manually remove threads from the TIdTCPServer::Threads property. You do not own the threads, TIdTCPServer does, and it will manage them for you. If you want to stop a given thread, closing the thread's socket is all you need to do. But by moving all of the sending logic into OnExecute where it belongs, you can let TIdTCPServer handle any errors and close the socket for you.
Your OnConnect event handler is setting AThread->Data only if an IG client connects, but your OnConnect and OnDisconnect handlers are not checking for that condition before attempting to access the TClient object.
Your OnDisconnect event handler is leaking memory if IsClosing is true. And it is calling Threads->UnlockList() without calling Threads->LockList() first. Attempting to unlock the list when it is not locked by the calling thread will cause errors and deadlocks.
Try something more like this:
struct TClient
{
AnsiString PeerIP; //{ Client IP address }
AnsiString HostName; //{ Hostname }
int Id; //{ Client ID }
};
void CALLBACK mmTimerProc(UINT wTimerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
TfmMain *pMain = (TfmMain *)dwUser;
if (pMain->IsClosing || pMain->Shutdown) return;
pMain->UpdateServer1Data();
// make sure pMain->Data2Client is thread-safe...
// set a signal that Data2Client has been updated...
// Shutdown computer or close application
if (pMain->SimIos.Status.iSimStatus == 11)
{
pMain->Shutdown = true;
pMain->CloseApp();
}
}
void __fastcall TfmMain::IdTCPServer1Connect(TIdPeerThread *AThread)
{
TClient *pClient;
AnsiString ABuffer, text;
AnsiString PeerIP = AThread->Connection->Binding->PeerIP;
TDateTime TimeConnected = Now();
ABuffer = AThread->Connection->ReadLn();
if ((ABuffer.Pos("TT") == 0) && (ABuffer.Pos("IG") == 0) && (ABuffer.Pos("RR") == 0))
{
text = AnsiString().sprintf("1>>> Unknown(%s) on %s connected illegal!...", PeerIP.c_str(), DateTimeToStr(TimeConnected).c_str());
WriteMsg(text);
AThread->Connection->Disconnect();
return;
}
pClient = new TClient;
pClient->PeerIP = PeerIP;
if (ABuffer.Pos("IG") != 0)
{
pClient->HostName = Clients[eIG];
pClient->Id = eIG;
}
else
pClient->Id = 0;
AThread->Data = (TObject *)pClient;
// Report client is on line
text = AnsiString().sprintf("1>>>%s(%s) on %s on line!...", pClient->HostName.c_str(), PeerIP.c_str(), DateTimeToStr(TimeConnected).c_str());
WriteMsg(text);
}
void __fastcall TfmMain::IdTCPServer1Disconnect(TIdPeerThread *AThread)
{
TClient *pClient = (TClient *)AThread->Data;
AnsiString Msg;
AThread->Data = NULL;
if (pClient)
{
// Report client is off line
Msg = AnsiString().sprintf("1>>>%s(%s) on %s off line...",
pClient->HostName.c_str(), pClient->PeerIP.c_str(), DateTimeToStr(Now()).c_str());
WriteMsg(Msg);
delete pClient;
}
}
void __fastcall TfmMain::IdTCPServer1Execute(TIdPeerThread *AThread)
{
TClient *pClient;
if (IsClosing) return;
// make sure pMain->Data2Client is thread-safe...
if (Data2Client has been updated since last event)
{
AThread->Connection->WriteBuffer(&pMain->Data2Client, sizeof(pMain->Data2Client), true);
}
pClient = (TClient *)AThread->Data;
// Report client still alive
}

Resources