ESP NOW failing using WIFI_AP_STA and WiFi.begin but working without the WiFi.begin - wifi

I am using code derived from Rui Santos https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
I am using ESP NOW to send readings from an ESP32 sender to an ESP32 receiver then using the ESP32 receiver to send an html message to a ESP32 web server. Per Rui's instructions I need to start WiFi with WIFI_AP_STA to allow both wifi connection methods.
The sender and receiver code is below.
If I run the code as is, i.e. the receiver setup as WIFI_AP_STA but with the WiFi.begin line commented out, I get a sender status of:
Send success, and a receive status of:Receive status. SO there is no problem sending an ESP NOW message from the sender to the receiver (also works with WIFI_STA).
If I use WIFI_AP_STA and uncomment the line in the receiver "WiFi.begin(SSIS, PASSWORD)" so that I can send a message to the ESP32 web server, I get a send status of:Send fail, and a receive status of:Receive status with failed send. The send fails but the receive is still successful. Same fail if I use WIFI_AP. It seems that in WIFI_AP_STA mode with a WiFi.begin, the receiver sends an incorrect status back to the sender.
In summary, on the receiver, using wifi mode WIFI_AP_STA without a WiFi.begin, works for sending an ESP NOW message from sender to receiver, as it should.
Using wifi mode WIFI_AP_STA and WiFi.begin on the receiver, the sender fails when sending an ESP NOW message. When I implement the web code the web html message send works. However the issue can be reproduced using the simplified code below.
Using WiFi#2.0.0.
I've run out of ideas, is anyone able to point me at further investigation areas?
My sender code is:
#include <Arduino.h>
#include <WiFi.h>
#include <esp_now.h>
// Rui Santos https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
uint8_t broadcastAddress[] = {0x24, 0x6F, 0x28, 0xAA, 0x84, 0x10};
typedef struct struct_message
{
char ESP32NowText[33];
} struct_message;
struct_message ESP32NowMessage;
//
String text = "AAA000010000200003000040000500006";
esp_now_peer_info_t peerInfo;
// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status)
{
Serial.print("\r\nLast Packet Send Status:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK)
{
Serial.println("Error initializing ESP-NOW");
return;
}
esp_now_register_send_cb(OnDataSent);
// Register peer
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
// Add peer
if (esp_now_add_peer(&peerInfo) != ESP_OK)
{
Serial.println("Failed to add peer");
return;
}
}
void loop()
{
strncpy(ESP32NowMessage.ESP32NowText, text.c_str(), text.length());
Serial.println("Msg to send:" + String(ESP32NowMessage.ESP32NowText));
Serial.println("Snd Len:" + String(sizeof(ESP32NowMessage)));
// Send message via ESP-NOW
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *)&ESP32NowMessage, sizeof(ESP32NowMessage));
if (result == ESP_OK)
{
Serial.println("Sent with success");
}
else
{
Serial.println("Error sending the data");
}
delay(2000);
}
My receiver code is:
#include <Arduino.h>
#include <WiFi.h>
#include <esp_now.h>
// Rui Santos https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
typedef struct struct_message
{
char ESP32NowValues[33];
} struct_message;
struct_message ESP32NowMessage;
// callback function that will be executed when data is received
void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len)
{
memcpy(&ESP32NowMessage, incomingData, sizeof(ESP32NowMessage));
Serial.println("Bytes received: " + String(len));
Serial.println("Values:" + String(ESP32NowMessage.ESP32NowValues));
Serial.println("---------------------------------------");
}
const char WiFiSSID[] = "SSID";
const char WiFiPassword[] = "PASSWORD";
//
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_AP_STA);
// WiFi.begin(WiFiSSID, WiFiPassword);
// Init ESP-NOW
if (esp_now_init() != ESP_OK)
{
Serial.println("Error initializing ESP-NOW");
return;
}
esp_now_register_recv_cb(OnDataRecv);
}
void loop()
{
}

Related

ESP8266 Subscribe to AWS IOT topic

Hi I need to create a lambda function which will access the AWS thing and publish MQTT message, I'd like to get the published message on the ESP8266 which was connected to the thing as well, and controlled turn on/off the LED on ESP8266. So far I have uploaded the private.der, cert.der and ca.der to the ESP8266 absolutely, but it couldn't subscribed AWS IOT, please point me in the right tips then please share.
Code:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <ArduinoJson.h>
#define OUT_TOPIC "$aws/things/devices/shadow/update"
#define IN_TOPIC "$aws/things/devices/shadow/update/delta"
const char* ssid = "sid";
const char* password = "password";
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");
const char* AWS_endpoint = "endpoint.amazonaws.com";//MQTT broker ip
const char* json = "{\"state\":{\"reported\":{\"led\":\"off\"}}}";
StaticJsonDocument<1024> doc;
WiFiClientSecure espClient;
PubSubClient mqttClient(espClient);//set MQTT port number to 8883 as per standard
PubSubClient client(AWS_endpoint, 8883, espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
void setup_wifi() {
delay(10);// We start by connecting to a WiFi network
espClient.setBufferSizes(512, 512);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
timeClient.begin();
while(!timeClient.update()){
timeClient.forceUpdate();
}
espClient.setX509Time(timeClient.getEpochTime());
int qos = 0;//Maximum size of data that can be communicated
Serial.println(MQTT_MAX_PACKET_SIZE);
if(mqttClient.subscribe(IN_TOPIC, qos)){
Serial.println("Subscribed.");
Serial.println("Success!!");
}
deserializeJson(doc, json);
JsonObject obj = doc.as<JsonObject>();
if(mqttClient.publish(OUT_TOPIC, json)){
Serial.println("Published!!");
}
}
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
setup_wifi();
delay(1000);
if (!SPIFFS.begin()) {
Serial.println("Failed to mount file system");
return;
}
Serial.print("Heap: "); Serial.println(ESP.getFreeHeap());
//replace cert.crt eith your uploaded file name
File cert = SPIFFS.open("/cert.der", "r");
if (!cert) {
Serial.println("Failed to open cert file");
}
else
Serial.println("Success to open cert file");
delay(1000);
if (espClient.loadCertificate(cert))
Serial.println("cert loaded");
else
Serial.println("cert not loaded");
// Load private key file
File private_key = SPIFFS.open("/private.der", "r");//replace private eith your uploaded file name
if (!private_key) {
Serial.println("Failed to open private cert file");
}
else
Serial.println("Success to open private cert file");
delay(1000);
if (espClient.loadPrivateKey(private_key))
Serial.println("private key loaded");
else
Serial.println("private key not loaded");
// Load CA file
File ca = SPIFFS.open("/ca.der", "r");
//replace ca eith your uploaded file name
if (!ca) {
Serial.println("Failed to open ca ");
}
else
Serial.println("Success to open ca");
delay(1000);
if(espClient.loadCACert(ca))
Serial.println("ca loaded");
else
Serial.println("ca failed");
Serial.print("Heap: ");
Serial.println(ESP.getFreeHeap());
}
void callback (char* topic, byte* payload, unsigned int length) {
Serial.println("Received. topic=");
Serial.println(topic);
char subsc[length];
for(int i=0; i<length; i++){
subsc [i]=(char)payload[i];
subsc [length]='\0';
Serial.print(subsc);
}
Serial.print("\n");
digitalWrite(LED_BUILTIN, HIGH);
}
void mqttLoop() {
mqttClient.loop();
delay(100);
//digitalWrite(LED_pin, LOW);
digitalWrite(LED_BUILTIN, LOW);
Serial.print(".");
}
void loop() {
It looks like you're using the older forms of WiFiClientSecure certificate handling. I'll assume that's working OK and you're able to establish an SSL connection.
Your IN_TOPIC needs to be updated slightly to: $aws/things/<name-of-your-thing>/shadow/update/accepted (where hopefully you know what <name-of-your-thing> is). You can get this from the thing shadow on your AWS console.
Similarly AWS_endpoint needs updating: it should be of the form <random-stuff-specific-to-you>.iot.<region>.amazonaws.com. You can also find it from the same place as the MQTT topics.
You only want one instance of PubSubClient. I'll assume you delete client and keep mqttClient. You'll need to update the instantiation to include the AWS endpoint and port as you have done for client.
Before calling mqttClient.subscribe(...) you need to register the callback:
mqttClient.setCallback(::callback);
then connect to AWS:
mqttClient.connect("some-unique-name");
Finally, you need to edit PubSubClient.h (look for it in Arduino/libraries/PubSubClient/src) to update MQTT_MAX_PACKET_SIZE. The default is 128 and I've found that too small with AWS's messages. I've made mine 1024:
#define MQTT_MAX_PACKET_SIZE 1024
and that appears ample.
Once that compiles and runs you'll start seeing callback(...) called with the topics you've subscribed to and you can implement the function to do whatever you need.
The PubSubClient doesn't do much error reporting to help diagnose what's going on. I'm currently refactoring it a bit and including more diagnostic information and will eventually issue a pull request. Let me know if you'd like my hacked version before I get that far.

Always get -1 connection refused response from server

I am making a alert device on my node mcu board to report any orders made by customers on my application. The nodemcu should access the network using wifi and call the rest api. I tried researching many sites and modified the code several times, but the response is always -1, connection refused.
tried doing
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
ESP8266WiFiMulti WiFiMulti;
void setup() {
Serial.begin(9600);
// Serial.setDebugOutput(true);
Serial.println();
Serial.println();
Serial.println();
for (uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
WiFi.mode(WIFI_STA);
WiFiMulti.addAP("----", "----");
}
void loop() {
// wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) {
WiFiClient client;
HTTPClient http;
Serial.print("[HTTP] begin...\n");
if (http.begin(client, "http://34.87.116.113:80/api/v1/iot/Notify/poll")) { // HTTP
http.setAuthorization("admin", "admin123!");
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 || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String payload = http.getString();
Serial.println(payload);
}
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
} else {
Serial.printf("[HTTP} Unable to connect\n");
}
}
delay(5000);
}

MQTT NodeMCU servo can react only on decimal array payload

I'm creating a fish feeder with SG90 servo and NodeMCU
I used this sketch:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Servo.h>
// Update these with values suitable for your network.
const char* ssid = "your_wifi_hotspot";
const char* password = "your_wifi_password";
const char* mqtt_server = "broker.mqttdashboard.com";
//const char* mqtt_server = "iot.eclipse.org";
Servo myservo; // create servo object to control a servo
WiFiClient espClient;
PubSubClient client(espClient);
void setup_wifi() {
delay(100);
// We start by connecting to a WiFi network
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length)
{
Serial.print("Command from MQTT broker is : [");
Serial.print(topic);
for(int i=0;i<length;i++)
{
if((int)payload[i]>194||(int)payload[i]<0)
break;
myservo.write((int)payload[i]); // tell servo to go to position in variable '(int)payload[i]'
}
}//end callback
void reconnect() {
// Loop until we're reconnected
while (!client.connected())
{
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
//if you MQTT broker has clientID,username and password
//please change following line to if (client.connect(clientId,userName,passWord))
if (client.connect(clientId.c_str()))
{
Serial.println("connected");
//once connected to MQTT broker, subscribe command if any
client.subscribe("OsoyooCommand");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 6 seconds before retrying
delay(6000);
}
}
} //end reconnect()
void setup() {
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
myservo.attach(D1); // attaches the servo on pin D1 to the servo object
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
}
The servo is working when I use MQTTBox in order to send a payload as "Decimal Array", it is however is giving me a hard time when I send payload as JSON string.
If I send "Decimal Array" 1 it does turn Servo to position 1, however if I simply send 1 as a payload as a string it moves Servo to position 49.
If I send payload as 2 it moves to position 50.
If I send payload as 10 then position is 4948
looks like position of 1 and position of 0 at the same time.
My ultimate goal is to send those payloads via HomeAssistant which are sent as string or JSON, however I don't find a correct solution at the moment.
I would highly appreciate any help or solution.
MQTT payloads are UTF-8 encoded so the Arduino PubSubClient library treats the payload as an array of uint8_t.
If you want to send and receive JSON then you can use the ArduinoJson library to parse a JSON payload. So assuming a JSON payload like:
{
"position": 123
}
Then you can implement a callback such as:
#include <ArduinoJson.h>
// Assuming a fixed sized JSON buffer
StaticJsonBuffer<200> jsonBuffer;
void callback(char* topic, byte* payload, unsigned int length)
{
JsonObject& root = jsonBuffer.parseObject(payload);
if (root.success() && root.is<JsonObject>())
{
int position = root.as<JsonObject>().get<int>("position");
myservo.write(position);
}
}
Looks like the motor is taking the position of the ASCII equivalent of the number when you send it as a string.
i.e.
ASCII equivalent of the character '1' in 49 in decimal
ASCII equivalent of the character '2' in 50 in decimal
Try sending the character 'a', the motor will go to 97.
If you want to send a string, you will have to change the following code:
for(int i=0;i<length;i++)
{
if((int)payload[i]>194||(int)payload[i]<0)
break;
myservo.write((int)payload[i]); // tell servo to go to position in variable '(int)payload[i]'
}
to:
int location=String((char*)payload).toInt()
if((location>194)||(location<0))
return;
myservo.write(location);

GET request failed in Arduino-Uno

I am trying to access a simple web page running in my Rpi-server using ESP8266 and Arduino.
I have refereed this similar SO question , but it's not the solution for my problem.
Here is my current Arduino Code :
#include "WiFiEsp.h"
// Emulate Serial1 on pins 6/7 if not present
#ifndef HAVE_HWSERIAL1
#include "SoftwareSerial.h"
SoftwareSerial Serial1(2,3); // RX, TX
#endif
char ssid[] = "RPi"; // your network SSID (name)
char pass[] = "raspberry"; // your network password
int status = WL_IDLE_STATUS; // the Wifi radio's status
char server[] = "192.168.50.1";
// Initialize the Ethernet client object
WiFiEspClient client;
void setup()
{
// initialize serial for debugging
Serial.begin(9600);
// initialize serial for ESP module
Serial1.begin(9600);
// initialize ESP module
WiFi.init(&Serial1);
// check for the presence of the shield
if (WiFi.status() == WL_NO_SHIELD) {
Serial.println("WiFi shield not present");
// don't continue
while (true);
}
// attempt to connect to WiFi network
while ( status != WL_CONNECTED) {
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network
status = WiFi.begin(ssid, pass);
}
// you're connected now, so print out the data
Serial.println("You're connected to the network");
printWifiStatus();
Serial.println();
Serial.println("Starting connection to server...");
// if you get a connection, report back via serial
if (client.connect(server, 80)) {
Serial.println("Connected to server");
// Make a HTTP request
client.println("GET /simple.html HTTP/1.1");
client.println("Host: 192.168.50.1");
client.println("Connection: close");
client.println();
}
}
void loop()
{
while (client.available()) {
char c = client.read();
Serial.write(c);
}
// if the server's disconnected, stop the client
if (!client.connected()) {
Serial.println();
Serial.println("Disconnecting from server...");
client.stop();
// do nothing forevermore
while (true);
}
void printWifiStatus()
{
// print the SSID of the network you're attached to
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your WiFi shield's IP address
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print the received signal strength
long rssi = WiFi.RSSI();
Serial.print("Signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
Output:
Starting connection to server...
[WiFiEsp] Connecting to 192.168.50.1
Connected to server
[WiFiEsp] Data packet send error (2)
[WiFiEsp] Failed to write to socket 3
[WiFiEsp] Disconnecting 3
My simple.html looks like this.
<html>
<body>
<p>1</p>
</body>
</html>
}
I accessed to this page from web browser and it shows the content properly.
What is missing here?
Thanks in advance.
Try this line in your code
client.print("GET /simple.html HTTP/1.0\r\n\r\n");

I can not subscribe with ESP8266-ESP32 in IBM Watson IOT

I want to subscribe to the "iot-2/evt/status/fmt/json" topic with ESP8266 on IBM Watson IOT. The connection is established but it is disconnecting again. So, reconnecting the MQTT client to … and subscribe to iot-2 / cmd / + / fmt / + OK. This cycle continues. Why is the connection broken?
My ESP8266 code is as follows.
I used an ESP8266-12E NodeMCU, I’ve created an Android app for the publisher.
/*
Basic ESP8266 MQTT example
This sketch demonstrates the capabilities of the pubsub library in combination
with the ESP8266 board/library.
It connects to an MQTT server then:
- publishes "hello world" to the topic "outTopic" every two seconds
- subscribes to the topic "inTopic", printing out any messages
it receives. NB - it assumes the received payloads are strings not binary
- If the first character of the topic "inTopic" is an 1, switch ON the ESP Led,
else switch it off
It will reconnect to the server if the connection is lost using a blocking
reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
achieve the same result without blocking the main loop.
To install the ESP8266 board, (using Arduino 1.6.4+):
- Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs":
http://arduino.esp8266.com/stable/package_esp8266com_index.json
- Open the "Tools -> Board -> Board Manager" and click install for the ESP8266"
- Select your ESP8266 in "Tools -> Board"
*/
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
//#include <ESP8266HTTPClient.h>
#include <SPI.h>
#include <ArduinoJson.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
//ZYxel
#define ssid "......."
#define password ".................."
//GES ARGE
#define ssid2 "..............." // WiFi SSID
#define password2 "............." // WiFi password
#define spi_ss_pin SS
#define ORG "............"
#define DEVICE_TYPE "........."
#define DEVICE_ID "..........."
#define TOKEN "................"
//-------- Customise the above values --------
char server[] = ORG ".messaging.internetofthings.ibmcloud.com";
int mqttPort=1883;
const char topic[] = "iot-2/cmd/status/fmt/json"; //"iot-2/cmd/status/fmt/json";
char authMethod[] = "use-token-auth";
char token[] = TOKEN;
char clientId[] = "d:" ORG ":" DEVICE_TYPE ":" DEVICE_ID;
WiFiClient wifiClient;
void callback(char* topic, byte* payload, unsigned int payloadLength) ;
PubSubClient client(server, 1883, callback, wifiClient);
void setup() {
Serial.begin(115200);
Serial.println();
wifiConnect();
mqttConnect();
}
void loop() {
if (!client.loop()) {
mqttConnect();
}
}
void wifiConnect() {
Serial.print("Connecting to "); Serial.print(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.print("nWiFi connected, IP address: "); Serial.println(WiFi.localIP());
}
void mqttConnect() {
if (!client.connected()) {
Serial.print("Reconnecting MQTT client to "); Serial.println(server);
while (!client.connect(clientId, authMethod, token)) {
Serial.print(".");
delay(500);
}
initManagedDevice();
Serial.println();
}
}
void initManagedDevice() {
if (client.subscribe(topic)) {
Serial.println("subscribe to cmd OK");
} else {
Serial.println("subscribe to cmd FAILED");
}
}
void callback(char* topic, byte* payload, unsigned int payloadLength) {
Serial.print("callback invoked for topic: "); Serial.println(topic);
for (int i = 0; i < payloadLength; i++) {
Serial.print((char)payload[i]);
}
}
A device ("use-token-auth" authentication type) cannot subscribe to a topic like "iot-2/evt/status/fmt/json" only "iot-2/cmd/status/fmt/json" is allowed.
What you need to do is to generate an API key and token and authenticate as an application:
The following example shows a typical API key:
a-orgId-a84ps90Ajs
The following example shows a typical authentication token:
MP$08VKz!8rXwnR-Q*
When you make an MQTT connection by using an API key, ensure that the following guidelines are applied:
The MQTT client ID is in the format: a:orgId:appId
The MQTT user name is the API key (for example, a-orgId-a84ps90Ajs)
The MQTT password is the authentication token (for example, MP$08VKz!8rXwnR-Q*)
After that you can subscribe to topic like iot-2/type/device_type/id/device_id/evt/event_id/fmt/format_string. So it should be:
iot-2/type/yourDeviceType/id/yourDeviceId/evt/status/fmt/json
You can use the same for commands: this how the topic should look like
iot-2/type/device_type/id/device_id/cmd/command_id/fmt/format_string

Resources