Error in uploading sensor data to Azure IOT central - azure-iot-hub

I have watched this video and tried to implement the same using all the required components and I have been getting errors in getting connected to the portal and am neither getting output from sensors.
this is the code that I have been using:
`
#include "DHT.h" // including the library of DHT11 temperature and humidity sensor
#include <ESP8266WiFi.h>
#define DHTTYPE DHT11
#include "D:/ARDUINO/ESP8266/ESP8266/src/iotc/common/string_buffer.h"
#include "D:/ARDUINO/ESP8266/ESP8266/src/iotc/iot"
#include "D:/ARDUINO/ESP8266/ESP8266/src/connection.h"
#define dht_dpin 12 // creating the object sensor on pin 'D12'
DHT dht(dht_dpin, DHTTYPE);
#define WIFI_SSID "<ENTER WIFI SSID>"
#define WIFI_PASSWORD "<ENTER WIFI PASSWORD>"
const char* SCOPE_ID = "<ENTER SCOPE ID>";
const char* DEVICE_ID = "<ENTER DEVICE ID>";
const char* DEVICE_KEY = "<ENTER DEVICE KEY>";
int echoPin = D6;
int trigPin = D8;
int pingTravelTime;
float pingTravelDistance;
float distanceToTarget;
float speedOfsound;
void on_event(IOTContext ctx, IOTCallbackInfo* callbackInfo);
void on_event(IOTContext ctx, IOTCallbackInfo* callbackInfo) {
// ConnectionStatus
if (strcmp(callbackInfo->eventName, "ConnectionStatus") == 0) {
LOG_VERBOSE("Is connected ? %s (%d)",
callbackInfo->statusCode == IOTC_CONNECTION_OK ? "YES" : "NO",
callbackInfo->statusCode);
isConnected = callbackInfo->statusCode == IOTC_CONNECTION_OK;
return;
}
// payload buffer doesn't have a null ending.
// add null ending in another buffer before print
AzureIOT::StringBuffer buffer;
if (callbackInfo->payloadLength > 0) {
buffer.initialize(callbackInfo->payload, callbackInfo->payloadLength);
}
LOG_VERBOSE("- [%s] event was received. Payload => %s\n",
callbackInfo->eventName, buffer.getLength() ? *buffer : "EMPTY");
if (strcmp(callbackInfo->eventName, "Command") == 0) {
LOG_VERBOSE("- Command name was => %s\r\n", callbackInfo->tag);
}
dht.begin();
}
void setup() {
Serial.begin(9600);
connect_wifi(WIFI_SSID, WIFI_PASSWORD);
connect_client(SCOPE_ID, DEVICE_ID, DEVICE_KEY);
if (context != NULL) {
lastTick = 0; // set timer in the past to enable first telemetry a.s.a.p
}
pinMode(trigPin,OUTPUT);
pinMode(echoPin,INPUT);
}
void loop() {
digitalWrite(trigPin,LOW);
delayMicroseconds(10);
digitalWrite(trigPin,HIGH);
delayMicroseconds(10);
digitalWrite(trigPin,LOW);
float h = dht.readHumidity();
float t = dht.readTemperature();
// Reading the temperature in Celsius degrees and store in the t variable
// Reading the humidity index and store in the h variable
pingTravelTime = pulseIn(echoPin,HIGH);
delay(25);
pingTravelDistance = (pingTravelTime*330*100)/(1000000);
speedOfsound = (pingTravelDistance*1000000)/pingTravelTime;
distanceToTarget = pingTravelDistance/2;
if (isConnected) {
unsigned long ms = millis();
if (ms - lastTick > 10000) { // send telemetry every 10 seconds
char msg[64] = {0};
int pos = 0, errorCode = 0;
lastTick = ms;
if (loopId++ % 4 == 0) { // send telemetry
pos = snprintf(msg, sizeof(msg) - 1, "{\"Temperature\": %f}",
t);
errorCode = iotc_send_telemetry(context, msg, pos);
pos = snprintf(msg, sizeof(msg) - 1, "{\"Humidity\":%f}",
h);
errorCode = iotc_send_telemetry(context, msg, pos);
pos = snprintf(msg, sizeof(msg) - 1, "{\"Distance\":%f}",
distanceToTarget);
errorCode = iotc_send_telemetry(context, msg, pos);
pos = snprintf(msg, sizeof(msg) - 1, "{\"Speed\":%f}",
speedOfsound);
errorCode = iotc_send_telemetry(context, msg, pos);
} else { // send property
}
msg[pos] = 0;
if (errorCode != 0) {
LOG_ERROR("Sending message has failed with error code %d", errorCode);
}
}
iotc_do_work(context); // do background work for iotc
} else {
iotc_free_context(context);
context = NULL;
connect_client(SCOPE_ID, DEVICE_ID, DEVICE_KEY);
}
delay(50);
}
`
I tried to implement this project for a thesis of mine and was not getting the results since the connection is not being established.
These are the errors i was getting:
ERROR: couldn't fetch the time from NTP. - -
X - Error at connection.h:32
Error # tcp_connect. Code 1 -
ERROR: Client was not connected. - -
iot.dps : getting auth... -
iotc.dps : getting operation id... -
ERROR: DPS endpoint PUT call has failed.
this is the github link for downloading the required header files for connection establishment

I could reproduce the same error in my NodeMCU. Please find the below image for reference.
If you let the code run and observe the NodeMCU serial monitor, it will occasionally spit out additional information as you can find in the below image
The error message in my case indicates that it is an issue with Authorization. I had the wrong Primary key provided in the code. In order to be able to connect to the device on Azure IoT Central, make sure the device is not set to be simulated when you create it.
Once you have the device created from the template, navigate to the device and click on connect to get the following details that needs to be entered in the code. Attached the below image for reference.
Here is the code snippet I have used to generate data
#include <ESP8266WiFi.h>
#include "src/iotc/common/string_buffer.h"
#include "src/iotc/iotc.h"
#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT11 // DHT 11
#define WIFI_SSID "<SSID>"
#define WIFI_PASSWORD "<WIFIPASSWORD>"
const char *SCOPE_ID = "<value 2 from above image>";
const char *DEVICE_ID = "<value 3 from above image>";
const char *DEVICE_KEY = "<value 4 from above image>";
DHT dht(DHTPIN, DHTTYPE);
void on_event(IOTContext ctx, IOTCallbackInfo *callbackInfo);
#include "src/connection.h"
void on_event(IOTContext ctx, IOTCallbackInfo *callbackInfo)
{
// ConnectionStatus
if (strcmp(callbackInfo->eventName, "ConnectionStatus") == 0)
{
LOG_VERBOSE("Is connected ? %s (%d)",
callbackInfo->statusCode == IOTC_CONNECTION_OK ? "YES" : "NO",
callbackInfo->statusCode);
isConnected = callbackInfo->statusCode == IOTC_CONNECTION_OK;
return;
}
// payload buffer doesn't have a null ending.
// add null ending in another buffer before print
AzureIOT::StringBuffer buffer;
if (callbackInfo->payloadLength > 0)
{
buffer.initialize(callbackInfo->payload, callbackInfo->payloadLength);
}
LOG_VERBOSE("- [%s] event was received. Payload => %s\n",
callbackInfo->eventName, buffer.getLength() ? *buffer : "EMPTY");
if (strcmp(callbackInfo->eventName, "Command") == 0)
{
LOG_VERBOSE("- Command name was => %s\r\n", callbackInfo->tag);
}
}
void setup()
{
Serial.begin(9600);
connect_wifi(WIFI_SSID, WIFI_PASSWORD);
connect_client(SCOPE_ID, DEVICE_ID, DEVICE_KEY);
if (context != NULL)
{
lastTick = 0; // set timer in the past to enable first telemetry a.s.a.p
}
dht.begin();
}
void loop()
{
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isConnected)
{
unsigned long ms = millis();
if (ms - lastTick > 10000)
{ // send telemetry every 10 seconds
char msg[64] = {0};
int pos = 0, errorCode = 0;
lastTick = ms;
if (loopId++ % 2 == 0)
{ // send telemetry
pos = snprintf(msg, sizeof(msg) - 1, "{\"Temperature\": %f}",
t);
errorCode = iotc_send_telemetry(context, msg, pos);
pos = snprintf(msg, sizeof(msg) - 1, "{\"Humidity\":%f}",
h);
errorCode = iotc_send_telemetry(context, msg, pos);
}
else
{ // send property
}
msg[pos] = 0;
if (errorCode != 0)
{
LOG_ERROR("Sending message has failed with error code %d", errorCode);
}
}
iotc_do_work(context); // do background work for iotc
}
else
{
iotc_free_context(context);
context = NULL;
connect_client(SCOPE_ID, DEVICE_ID, DEVICE_KEY);
}
}
Here are the Temperature and Humidity values generated from the code
The data generated the following graph on the Azure IoT Central.
Please note that I have used DHT11 sensor and connected to read it from the GPI0 2 (D4) pin on my NodeMCU board. I have used the Arduino IDE version 1.8.19 and ESP8266 board version 2.7.4

Related

ESP32 Multitask Parameter pass through Spreadsheet

I am working for soil moisture and pressure sensor using the same baud-rate 115200 in ESP32. Plus, I execute both sensor using multitask ESP32 with 2 core. Core 1 and Core 2 for both program.
The parameter can be viewed through serial monitor however it can’t be passed through the spreadsheet. I am using IFTTT platform to connect the ESP32 into Spreadsheet.
Here my code :
#include <WiFi.h>
#include <HTTPClient.h>
TaskHandle_t Task1;
TaskHandle_t Task2;
const char * ssid = "XXXX";
const char * password = "XXXX";
String server = "http://maker.ifttt.com";
String eventName = "soil_pressure";
String IFTTT_Key = "XXXXXXXXXX";
String IFTTTUrl="https://maker.ifttt.com/trigger/soil_pressure/with/key/XXXXX";
int sensorPin = 2;
int sensorValueSoil;
int limit = 300;
int sensorValuePressure;
int value1; // soil
int value2; // pressure
void setup()
{
Serial.begin(115200);
pinMode(2, OUTPUT);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("Internet Connected !!!");
xTaskCreatePinnedToCore(
Task1code, /* Task function. */
"Task1", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
delay(500);
xTaskCreatePinnedToCore(
Task2code, /* Task function. */
"Task2", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task2, /* Task handle to keep track of created task */
1); /* pin task to core 1 */
delay(500);
}
void Task1code( void * pvParameters )
{
Serial.print("Task1 running on core ");
Serial.println(xPortGetCoreID());
for(;;)
{
sensorValueSoil = analogRead(sensorPin);
Serial.println(sensorValueSoil);
if (sensorValueSoil<limit)
{
digitalWrite(2, HIGH);
}
else {
digitalWrite(2, LOW);
}
delay(1000);
}
}
void Task2code( void * pvParameters )
{
Serial.print("Task2 running on core ");
Serial.println(xPortGetCoreID());
for(;;)
{
sensorValuePressure = analogRead(13);
Serial.println(sensorValuePressure);
delay(1000);
}
}
void sendDataToSheet(void)
{
String url = server + "/trigger/" + eventName + "/with/key/" + IFTTT_Key + "
value1=" + String((int)value1) + "&value2="+String((int)value2);
Serial.println(url);
//Start to send data to IFTTT
HTTPClient http;
Serial.print("[HTTP] begin...\n");
http.begin(url); //HTTP
Serial.print("[HTTP] GET...\n");
// start connection and send HTTP header
int httpCode = http.GET();
// httpCode will be negative on error
if(httpCode > 0)
{
// HTTP header has been send and Server
response header has been handled
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server
if(httpCode == HTTP_CODE_OK) {
String payload = http.getString();
Serial.println(payload);
}
}
else
{
Serial.printf("[HTTP] GET... failed, error: %s\n",
http.errorToString(httpCode).c_str());
}
http.end();
}
void loop()
{
value1 = sensorValueSoil;
value2 = sensorValuePressure;
Serial.print("Values are ");
Serial.print(value1);
Serial.print(' ');
Serial.print(value2);
Serial.print(' ');
sendDataToSheet();
delay(5000);
}
You need to pass WiFiClient object into HTTPClient arguments.
HTTPClient http;
WiFiClient client;
void sendDataToSheet(void) {
String url = server + "/trigger/" + eventName + "/with/key/" + IFTTT_Key + "value1 = " + String((int)value1) + " & value2 = " + String((int)value2);
Serial.println(url);
//Start to send data to IFTTT
Serial.print("[HTTP] begin...\n");
http.begin(client, url);
// start connection and send HTTP header
int httpCode = http.GET();
// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
Serial.println(payload);
}
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
}

ESP8266 WIFI Connection lost after Acces Point reboot

Heyho,
at first, I am no programmer - it's just my hobby :)
I have a cistern in my garden and I want to measure the level of it with an ESP8266 and an ultrasonic sensor.
I am sending the data via mqtt to my mqtt broker.
Everything working well but when my accesspoint is rebooting two times a day and after that reboot the ESP8266 doesn't connect to the WIFI again.
What I've done so far:
setting the WiFi.setAutoReconnect(true); to true (find that in the Internet)
call the function setup(); in void loop() again
So, I think I have a mistake in thinking with that problem.
Heres my code:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Ultrasonic.h>
Ultrasonic ultrasonic(12, 13);
const char* ssid = "XXX"; // Enter your WiFi name
const char* password = "XXX"; // Enter WiFi password
const char* mqttServer = "XXX";
const int mqttPort = 1883;
const char* mqttUser = "XXX";
const char* mqttPassword = "XXX";
#define abstand_topic "home/zisterne/fuellstand"
#define abstand_topic_2 "home/zisterne/mittl_fuellstand"
const int RunningAverageCount = 24; // Anzahl der in den Laufenden-Mettelwert aufgenommenen Messungen
float RunningAverageBuffer[RunningAverageCount];
int NextRunningAverage;
unsigned long previousMillis = 0;
unsigned long interval = 30000;
WiFiClient espClient;
PubSubClient client(espClient);
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
WiFi.setAutoReconnect(true);
WiFi.persistent(true);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting to WiFi..");
}
Serial.println("Connected to the WiFi network");
client.setServer(mqttServer, mqttPort);
client.setCallback(callback);
while (!client.connected()) {
Serial.println("Connecting to MQTT...");
if (client.connect("ESP8266Client", mqttUser, mqttPassword )) {
Serial.println("connected");
} else {
Serial.print("failed with state ");
Serial.print(client.state());
delay(2000);
}
}
// //Sensor auslesen und übergeben
// int Sensor = ultrasonic.distanceRead();
// char Abstand[10];
// itoa(Sensor,Abstand,10);
//
// Serial.println(ultrasonic.distanceRead());
// client.publish(abstand_topic, Abstand);
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived in topic: ");
Serial.println(topic);
Serial.print("Message:");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
Serial.println("-----------------------");
}
void loop() {
client.loop();
//WLAN Reconnect
if (WiFi.status() != WL_CONNECTED) {
delay(500);
setup();
}
//Sensor auslesen und übergeben
int Sensor = ultrasonic.distanceRead();
char Abstand[10];
itoa(Sensor,Abstand,10);
Serial.println(ultrasonic.distanceRead());
client.publish(abstand_topic, Abstand);
//unsigned long minutes = 1000 * 300;
float RawDistance = ultrasonic.distanceRead();
RunningAverageBuffer[NextRunningAverage++] = RawDistance;
if (NextRunningAverage >= RunningAverageCount)
{
NextRunningAverage = 0;
}
float RunningAverageDistance = 0;
for(int i=0; i< RunningAverageCount; ++i)
{
RunningAverageDistance += RunningAverageBuffer[i];
}
RunningAverageDistance /= RunningAverageCount;
int mittelwert = RunningAverageDistance;
char mittl_Abstand[10];
itoa(mittelwert,mittl_Abstand,10);
client.publish(abstand_topic_2, mittl_Abstand);
delay(5000);
yield();
}
So, now I hope someone of you can help me with my small problem! :)
Greetings,
Philipp

ESP8266 Sniffing and sending Mac address

I'm trying to make my ESP8266 sniffing nearby devices, then posting them by with a HTTP request. With purpose is to record when my roommate and I are at home. Then in the future, trigger certain tasks like turning on/off the lights if we're home or not. I don't care at all about the packets content just the mac addresses.
So fare I've found this, script that prints out the mac adresses for nearby devices, created by kalanda: esp8266-sniffer.
Aswell as this HTTP posting script ESP8266 http get requests.
I've tried to combine those two and in the callback function make the ESP send the found data, but doesn't look like the ESP establish the wifi connection.
I tried using different WIFI modes: STATION_MODE, SOFTAP_MODE, STATIONAP_MODE. None of them worked for both sniffing and http request at the same time. I know that the STATIONAP_MODE do have some flaws. What I've found is that it has to switch both somehow, but unfortunately I'm not a ESP expert and don't know how this can be done.
Here is my code(srry for any rubbish coding on my side):
#include <ESP8266WiFi.h> // added this
#include <ESP8266HTTPClient.h> // added this
const char* ssid = "**********"; // Wifi SSID
const char* password = "**********"; // Wifi Password
String main_url = "http://*********.php?"; // Website url to post the information
String temp_url = ""; // Url with information
extern "C" {
#include <user_interface.h>
}
#define DATA_LENGTH 112
#define TYPE_MANAGEMENT 0x00
#define TYPE_CONTROL 0x01
#define TYPE_DATA 0x02
#define SUBTYPE_PROBE_REQUEST 0x04
struct RxControl {
signed rssi:8; // signal intensity of packet
unsigned rate:4;
unsigned is_group:1;
unsigned:1;
unsigned sig_mode:2; // 0:is 11n packet; 1:is not 11n packet;
unsigned legacy_length:12; // if not 11n packet, shows length of packet.
unsigned damatch0:1;
unsigned damatch1:1;
unsigned bssidmatch0:1;
unsigned bssidmatch1:1;
unsigned MCS:7; // if is 11n packet, shows the modulation and code used (range from 0 to 76)
unsigned CWB:1; // if is 11n packet, shows if is HT40 packet or not
unsigned HT_length:16;// if is 11n packet, shows length of packet.
unsigned Smoothing:1;
unsigned Not_Sounding:1;
unsigned:1;
unsigned Aggregation:1;
unsigned STBC:2;
unsigned FEC_CODING:1; // if is 11n packet, shows if is LDPC packet or not.
unsigned SGI:1;
unsigned rxend_state:8;
unsigned ampdu_cnt:8;
unsigned channel:4; //which channel this packet in.
unsigned:12;
};
struct SnifferPacket{
struct RxControl rx_ctrl;
uint8_t data[DATA_LENGTH];
uint16_t cnt;
uint16_t len;
};
static void showMetadata(SnifferPacket *snifferPacket) {
unsigned int frameControl = ((unsigned int)snifferPacket->data[1] << 8) + snifferPacket->data[0];
uint8_t version = (frameControl & 0b0000000000000011) >> 0;
uint8_t frameType = (frameControl & 0b0000000000001100) >> 2;
uint8_t frameSubType = (frameControl & 0b0000000011110000) >> 4;
uint8_t toDS = (frameControl & 0b0000000100000000) >> 8;
uint8_t fromDS = (frameControl & 0b0000001000000000) >> 9;
// Only look for probe request packets
if (frameType != TYPE_MANAGEMENT ||
frameSubType != SUBTYPE_PROBE_REQUEST)
return;
Serial.print("RSSI: ");
Serial.print(snifferPacket->rx_ctrl.rssi, DEC);
Serial.print(" Ch: ");
Serial.print(wifi_get_channel());
char addr[] = "00:00:00:00:00:00";
getMAC(addr, snifferPacket->data, 10);
Serial.print(" Peer MAC: ");
Serial.print(addr);
uint8_t SSID_length = snifferPacket->data[25];
Serial.print(" SSID: ");
printDataSpan(26, SSID_length, snifferPacket->data);
Serial.println();
if (WiFi.status() == WL_CONNECTED) //Check WiFi connection status
{
HTTPClient http; //Declare an object of class HTTPClient
temp_url = main_url;
temp_url = temp_url + "mac=30:a8:db:96:a4:75";
temp_url = temp_url + "&rssi=-90";
temp_url = temp_url + "&ssid=none";
http.begin(temp_url); //Specify request destination
int httpCode = http.GET(); //Send the request
temp_url = "";
if (httpCode > 0)
{ //Check the returning code
String payload = http.getString(); //Get the request response payload
Serial.println(payload); //Print the response payload
}
http.end(); //Close connection
}
else
{
Serial.println("Wifi connection failed"); //Prints out this
}
}
/**
* Callback for promiscuous mode
*/
static void ICACHE_FLASH_ATTR sniffer_callback(uint8_t *buffer, uint16_t length) {
struct SnifferPacket *snifferPacket = (struct SnifferPacket*) buffer;
showMetadata(snifferPacket);
}
static void printDataSpan(uint16_t start, uint16_t size, uint8_t* data) {
for(uint16_t i = start; i < DATA_LENGTH && i < start+size; i++) {
Serial.write(data[i]);
}
}
static void getMAC(char *addr, uint8_t* data, uint16_t offset) {
sprintf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", data[offset+0], data[offset+1], data[offset+2], data[offset+3], data[offset+4], data[offset+5]);
}
#define CHANNEL_HOP_INTERVAL_MS 1000
static os_timer_t channelHop_timer;
/**
* Callback for channel hoping
*/
void channelHop()
{
// hoping channels 1-14
uint8 new_channel = wifi_get_channel() + 1;
if (new_channel > 14)
new_channel = 1;
wifi_set_channel(new_channel);
}
#define DISABLE 0
#define ENABLE 1
void setup() {
// set the WiFi chip to "promiscuous" mode aka monitor mode
Serial.begin(115200);
delay(10);
wifi_set_opmode(STATION_MODE);
wifi_set_channel(1);
wifi_promiscuous_enable(DISABLE);
delay(10);
wifi_set_promiscuous_rx_cb(sniffer_callback);
delay(10);
wifi_promiscuous_enable(ENABLE);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print("Connecting..");
}
Serial.println("");
Serial.println("Connected..");
// setup the channel hoping callback timer
os_timer_disarm(&channelHop_timer);
os_timer_setfn(&channelHop_timer, (os_timer_func_t *) channelHop, NULL);
os_timer_arm(&channelHop_timer, CHANNEL_HOP_INTERVAL_MS, 1);
}
void loop() {
delay(10);
}
Here's the code which aggregates probe requests (MAC addresses and RSSIs) for 3 seconds and then sends them to specified server's endpoint using json (WIFI_AP_STA mode):
#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266HTTPClient.h>
#include <vector>
const char* apSsid = "ap-ssid";
const char* apPassword = "ap-password";
const char* clientSsid = "client-ssid";
const char* clientPassword = "client-password";
HTTPClient http;
WiFiEventHandler probeRequestPrintHandler;
String macToString(const unsigned char* mac) {
char buf[20];
snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return String(buf);
}
std::vector<WiFiEventSoftAPModeProbeRequestReceived> myList;
void onProbeRequestPrint(const WiFiEventSoftAPModeProbeRequestReceived& evt) {
myList.push_back(evt);
}
void setup() {
Serial.begin(115200);
Serial.println("Hello!");
// Don't save WiFi configuration in flash - optional
WiFi.persistent(false);
WiFi.mode(WIFI_AP_STA);
WiFi.softAP(apSsid, apPassword);
WiFi.begin(clientSsid, clientPassword);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(100);
}
Serial.println("");
probeRequestPrintHandler = WiFi.onSoftAPModeProbeRequestReceived(&onProbeRequestPrint);
}
void loop() {
delay(3000);
String json = "";
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
JsonArray& probes = root.createNestedArray("probes");
for(WiFiEventSoftAPModeProbeRequestReceived w : myList){
JsonObject& probe = probes.createNestedObject();
probe["address"] = macToString(w.mac);
probe["rssi"] = w.rssi;
}
myList.clear();
root.printTo(json);
Serial.println("json:" + json);
http.begin("http://example.com/api/v1/probe");
http.addHeader("Content-Type", "application/json");
http.POST(json);
http.end();
}
Remember to use the latest version (actually a pre-release - 2.4.0-rc1 or newer) of arduino-esp8266 library since those WiFiEvents were just recently added.
You can download ArduinoJson library using Library Manager (Sketch -> Include Library -> Manage Libraries...) if you don't have that already.

How to listen continuosly SSDP response after sending M-SEARCH

I would like to search Sat>IP servers on the network. Sat>IP servers advertise their presence to other Sat>IP servers and clients.
I must not continuosly send M-SEARCH messages but that instead it listens to server NOTIFY messages.
After initalizing network settings of my device, I'm sending M-SEARCH message and getting response if there is already any active Sat>IP server.
However, I couldn't get any response, If I opens Sat>IP server after sending M-SEARCH message.
Here's my code.
void SatIP::InitDiscoverThread()
{
if(INVALID_THREAD_CHK == DiscoverThreadChk)
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, PTHREAD_STACK_SIZE);
printf("InitDiscoverThread pthread_create\n");
DiscoverThreadChk = PTH_RET_CHK(pthread_create(&DiscoverThreadID, &attr, DiscoverThreadFunc, this));
if(DiscoverThreadChk != 0)
{
ASSERT(0);
}
}
}
void SatIP::FinalizeDiscoverThread()
{
if(INVALID_THREAD_CHK != DiscoverThreadChk)
{
printf("FinalizeDiscoverThread pthread_cancel\n");
pthread_cancel(DiscoverThreadID);
DiscoverThreadChk = INVALID_THREAD_CHK;
close(discoverSocket);
}
}
void *SatIP::DiscoverThreadFunc(void* arg)
{
SatIP* satip = (SatIP *)arg;
satip->ListenSSDPResponse();
pthread_exit(NULL);
}
bool SatIP::SendMSearchMessage()
{
vSatIPServers.clear();
FinalizeDiscoverThread();
const char *searchSatIPDevice = "M-SEARCH * HTTP/1.1\r\n" \
"HOST: 239.255.255.250:1900\r\n" \
"MAN: \"ssdp:discover\"\r\n" \
"MX: 2\r\n" \
"ST: urn:ses-com:device:SatIPServer:1\r\n\r\n";
struct sockaddr_in upnpControl, broadcast_addr;
discoverSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (discoverSocket == INVALID_SOCKET)
{
printf("socked failed INVALID_SOCKET\n");
return false;
}
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
if(setsockopt(discoverSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)) == SOCKET_ERROR)
{
printf("setsockopt timeout failed\n");
close(discoverSocket);
return false;
}
socklen_t ttl = 2;
if(setsockopt(discoverSocket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == SOCKET_ERROR)
{
printf("setsockopt TTL failed\n");
close(discoverSocket);
return false;
}
if(setsockopt(discoverSocket, SOL_SOCKET, SO_BROADCAST, searchSatIPDevice, sizeof(searchSatIPDevice)) == SOCKET_ERROR)
{
printf("setsockopt broadcast failed\n");
close(discoverSocket);
return false;
}
upnpControl.sin_family = AF_INET;
upnpControl.sin_port = htons(0);
upnpControl.sin_addr.s_addr = INADDR_ANY;
if (bind(discoverSocket, (sockaddr*)&upnpControl, sizeof(upnpControl)) == SOCKET_ERROR)
{
printf("bind failed\n");
close(discoverSocket);
return false;
}
broadcast_addr.sin_family = AF_INET;
broadcast_addr.sin_port = htons(1900);
broadcast_addr.sin_addr.s_addr = inet_addr("239.255.255.250");
for(int i = 0; i < 3; i++)
{
if(sendto(discoverSocket, searchSatIPDevice, strlen(searchSatIPDevice), 0, (sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) == SOCKET_ERROR)
{
//printf("sendto failed\n");
close(discoverSocket);
return false;
}
else
{
usleep(10*100);
}
}
InitDiscoverThread();
return true;
}
void SatIP::ListenSSDPResponse()
{
while(1)
{
char buf[512];
memset(buf, 0, 512);
struct sockaddr_in broadcast_addr;
broadcast_addr.sin_family = AF_INET;
broadcast_addr.sin_port = htons(1900);
broadcast_addr.sin_addr.s_addr = inet_addr("239.255.255.250");
int bcLen = sizeof(broadcast_addr);
//bool bRet = false;
while (recvfrom(discoverSocket, buf, 512, 0, (struct sockaddr*)&broadcast_addr, (socklen_t*)&bcLen) > 0)
{
printf("buf:%s\n",buf);
SATIP_SERVER_DESCRIPTION stServerDesc;
ostringstream ss;
if(strstr(buf, "device:SatIPServer"))
{
int i = 0;
char *deviceIp = strstr(buf, "LOCATION:") + 9; // get xml location including server description
while(deviceIp[i] == ' ') i++; // remove spaces from string
while(!isspace(deviceIp[i]))
{
ss << deviceIp[i];
++i;
}
stServerDesc.location = ss.str().c_str();
printf("location:%s\n",stServerDesc.location.c_str());
ss.str(""); // clear ss
i=0; // clear counter
deviceIp = strstr(buf, "http://") + 7; // get ip address
while(deviceIp[i] != ':')
{
ss << deviceIp[i];
++i;
}
stServerDesc.ipAddr = ss.str().c_str();
printf("ipAddr:%s\n", stServerDesc.ipAddr.c_str());
DownloadDeviceDescription(&stServerDesc);
stServerDesc.macAddr = GetMACAddressviaIP(stServerDesc.ipAddr);
printf("macAddr:%s\n", stServerDesc.macAddr.c_str());
if(IsServerProperToAdd(&stServerDesc))
vSatIPServers.push_back(stServerDesc);
printf("\n");
//bRet = true;
}
memset(buf, 0, 512);
}
}
}
How can I fix this issue? Any help would be appreciated.
Listening SSDP notify message is not related to sending M-SEARCH message. Devices like Sat>IP send NOTIFY message to 239.255.255.250 periodically even if you don't send M-SEARCH message. So, you should join a multicast group and receives from the group.
You can use the listener program in the following link by changing HELLO_PORT as 1900 and HELLO_GROUP as "239.255.255.250".
http://ntrg.cs.tcd.ie/undergrad/4ba2/multicast/antony/example.html
/*
* listener.c -- joins a multicast group and echoes all data it receives from
* the group to its stdout...
*
* Antony Courtney, 25/11/94
* Modified by: Frédéric Bastien (25/03/04)
* to compile without warning and work correctly
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define HELLO_PORT 1900
#define HELLO_GROUP "239.255.255.250"
#define MSGBUFSIZE 256
main(int argc, char *argv[])
{
struct sockaddr_in addr;
int fd, nbytes,addrlen;
struct ip_mreq mreq;
char msgbuf[MSGBUFSIZE];
u_int yes=1; /*** MODIFICATION TO ORIGINAL */
/* create what looks like an ordinary UDP socket */
if ((fd=socket(AF_INET,SOCK_DGRAM,0)) < 0) {
perror("socket");
exit(1);
}
/**** MODIFICATION TO ORIGINAL */
/* allow multiple sockets to use the same PORT number */
if (setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)) < 0) {
perror("Reusing ADDR failed");
exit(1);
}
/*** END OF MODIFICATION TO ORIGINAL */
/* set up destination address */
memset(&addr,0,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY); /* N.B.: differs from sender */
addr.sin_port=htons(HELLO_PORT);
/* bind to receive address */
if (bind(fd,(struct sockaddr *) &addr,sizeof(addr)) < 0) {
perror("bind");
exit(1);
}
/* use setsockopt() to request that the kernel join a multicast group */
mreq.imr_multiaddr.s_addr=inet_addr(HELLO_GROUP);
mreq.imr_interface.s_addr=htonl(INADDR_ANY);
if (setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq)) < 0) {
perror("setsockopt");
exit(1);
}
/* now just enter a read-print loop */
while (1) {
addrlen=sizeof(addr);
if ((nbytes=recvfrom(fd,msgbuf,MSGBUFSIZE,0,
(struct sockaddr *) &addr,&addrlen)) < 0) {
perror("recvfrom");
exit(1);
}
puts(msgbuf);
}
}

How to write NALs produced by x264_encoder_encode() using ffmpeg av_interleaved_write_frame()

I have been trying to produce a "flv" video file in the following sequence:
av_register_all();
// Open video file
if (avformat_open_input(&pFormatCtx, "6.mp4", NULL, NULL) != 0)
return -1; // Couldn't open file
// Retrieve stream information
if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
return -1; // Couldn't find stream information
// Dump information about file onto standard error
av_dump_format(pFormatCtx, 0, "input_file.mp4", 0);
// Find the first video stream
videoStream = -1;
for (i = 0; i < pFormatCtx->nb_streams; i++)
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
break;
}
if (videoStream == -1)
return -1; // Didn't find a video stream
// Get a pointer to the codec context for the video stream
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
// Find the decoder for the video stream
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (pCodec == NULL) {
fprintf(stderr, "Unsupported codec!\n");
return -1; // Codec not found
}
// Open codec
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
return -1; // Could not open codec
// Allocate video frame
pFrame = avcodec_alloc_frame();
// Allocate video frame
pFrame = avcodec_alloc_frame();
// Allocate an AVFrame structure
pFrameYUV420 = avcodec_alloc_frame();
if (pFrameYUV420 == NULL)
return -1;
// Determine required buffer size and allocate buffer
numBytes = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
// Assign appropriate parts of buffer to image planes in pFrameYUV420
// Note that pFrameYUV420 is an AVFrame, but AVFrame is a superset of AVPicture
avpicture_fill((AVPicture *) pFrameRGB, buffer, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
// Setup scaler
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, SWS_BILINEAR, 0, 0, 0);
if (img_convert_ctx == NULL) {
fprintf(stderr, "Cannot initialize the conversion context!\n");
exit(1);
}
// Setup encoder/muxing now
filename = "output_file.flv";
fmt = av_guess_format("flv", filename, NULL);
if (fmt == NULL) {
printf("Could not guess format.\n");
return -1;
}
/* allocate the output media context */
oc = avformat_alloc_context();
if (oc == NULL) {
printf("could not allocate context.\n");
return -1;
}
oc->oformat = fmt;
snprintf(oc->filename, sizeof(oc->filename), "%s", filename);
video_st = NULL;
if (fmt->video_codec != AV_CODEC_ID_NONE) {
video_st = add_stream(oc, &video_codec, fmt->video_codec);
}
// Let's see some information about our format
av_dump_format(oc, 0, filename, 1);
/* open the output file, if needed */
if (!(fmt->flags & AVFMT_NOFILE)) {
ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);
if (ret < 0) {
fprintf(stderr, "Could not open '%s': %s\n", filename, av_err2str(ret));
return 1;
}
}
/* Write the stream header, if any. */
ret = avformat_write_header(oc, NULL);
if (ret < 0) {
fprintf(stderr, "Error occurred when opening output file: %s\n", av_err2str(ret));
return 1;
}
// Setup x264 params
x264_param_t param;
x264_param_default_preset(&param, "veryfast", "zerolatency");
param.i_threads = 1;
param.i_width = video_st->codec->width;
param.i_height = video_st->codec->height;
param.i_fps_num = STREAM_FRAME_RATE; // 30 fps, same as video
param.i_fps_den = 1;
// Intra refres:
param.i_keyint_max = STREAM_FRAME_RATE;
param.b_intra_refresh = 1;
// Rate control:
param.rc.i_rc_method = X264_RC_CRF;
param.rc.f_rf_constant = 25;
param.rc.f_rf_constant_max = 35;
// For streaming:
param.b_repeat_headers = 1;
param.b_annexb = 1;
x264_param_apply_profile(&param, "baseline");
x264_t* encoder = x264_encoder_open(&param);
x264_picture_t pic_in, pic_out;
x264_picture_alloc(&pic_in, X264_CSP_I420, video_st->codec->width, video_st->codec->height);
x264_nal_t* nals;
int i_nals;
// The loop:
// 1. Read frames
// 2. Decode the frame
// 3. Attempt to re-encode using x264
// 4. Write the x264 encoded frame using av_interleaved_write_frame
while (av_read_frame(pFormatCtx, &packet) >= 0) {
// Is this a packet from the video stream?
if (packet.stream_index == videoStream) {
// Decode video frame
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
// Did we get a video frame?
if (frameFinished) {
sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pic_in.img.plane, pic_in.img.i_stride);
int frame_size = x264_encoder_encode(encoder, &nals, &i_nals, &pic_in, &pic_out);
if (frame_size >= 0) {
if (i_nals < 0)
printf("invalid frame size: %d\n", i_nals);
// write out NALs
for (i = 0; i < i_nals; i++) {
// initalize a packet
AVPacket p;
av_init_packet(&p);
p.data = nals[i].p_payload;
p.size = nals[i].i_payload;
p.stream_index = video_st->index;
p.flags = AV_PKT_FLAG_KEY;
p.pts = AV_NOPTS_VALUE;
p.dts = AV_NOPTS_VALUE;
ret = av_interleaved_write_frame(oc, &p);
}
}
printf("encoded frame #%d\n", frame_count);
frame_count++;
}
}
// Free the packet that was allocated by av_read_frame
av_free_packet(&packet);
}
// Now we free up resources used/close codecs, and finally close our program.
Here is the implementation for the add_stream() function:
/* Add an output stream. */
static AVStream *add_stream(AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id) {
AVCodecContext *c;
AVStream *st;
int r;
/* find the encoder */
*codec = avcodec_find_encoder(codec_id);
if (!(*codec)) {
fprintf(stderr, "Could not find encoder for '%s'\n",
avcodec_get_name(codec_id));
exit(1);
}
st = avformat_new_stream(oc, *codec);
if (!st) {
fprintf(stderr, "Could not allocate stream\n");
exit(1);
}
st->id = oc->nb_streams - 1;
c = st->codec;
switch ((*codec)->type) {
case AVMEDIA_TYPE_AUDIO:
st->id = 1;
c->sample_fmt = AV_SAMPLE_FMT_FLTP;
c->bit_rate = 64000;
c->sample_rate = 44100;
c->channels = 2;
break;
case AVMEDIA_TYPE_VIDEO:
avcodec_get_context_defaults3(c, *codec);
c->codec_id = codec_id;
c->bit_rate = 500*1000;
//c->rc_min_rate = 500*1000;
//c->rc_max_rate = 500*1000;
//c->rc_buffer_size = 500*1000;
/* Resolution must be a multiple of two. */
c->width = 1280;
c->height = 720;
/* timebase: This is the fundamental unit of time (in seconds) in terms
* of which frame timestamps are represented. For fixed-fps content,
* timebase should be 1/framerate and timestamp increments should be
* identical to 1. */
c->time_base.den = STREAM_FRAME_RATE;
c->time_base.num = 1;
c->gop_size = 12; /* emit one intra frame every twelve frames at most */
c->pix_fmt = STREAM_PIX_FMT;
if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
/* just for testing, we also add B frames */
c->max_b_frames = 2;
}
if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
/* Needed to avoid using macroblocks in which some coeffs overflow.
* This does not happen with normal video, it just happens here as
* the motion of the chroma plane does not match the luma plane. */
c->mb_decision = 2;
}
break;
default:
break;
}
/* Some formats want stream headers to be separate. */
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
return st;
}
After the encoding is complete, I check the output file output_file.flv. I notice it's size is very large: 101MB and it does not play. If I use ffmpeg to decode/encode the input file, then I get an output file about 83MB in size (which is about the same size as the original .mp4 file used as input). Also, the 83MB output from just using ffmpeg C api, as opposed to using x264 for the encoding step, plays just fine. Does anyone know where I am going wrong? I have tried researching this for a few days now but with no luck :(. I feel that I am close to making it work, however, I just cannot figure out what I am doing wrong. Thank you!
To produce the correct AVPacket, you should write all nals into the same packet, as it is done in http://ffmpeg.org/doxygen/trunk/libx264_8c_source.html (see encode_nals and X264_frame functions)