I am trying to connect a WeMos D1 mini based on ESP8266 to the Amazon Web Service AWS IoT using https://github.com/heskew/aws-sdk-arduino.
However, when I flash the device, I get a 403 back, with the following message:
"Credential should be scoped to correct service: 'execute-api'. "
Changing
this->awsService = "iotdata";
to
this->awsService = "execute-api";
in AmazonIOTClient.cpp results in a 404:
"No method found matching route things/my-thing/shadow for http method POST."
and, according to this thread the service should be 'iotdata' for the request to succeed.
Has someone had the same problem and figured out a way to get it running? If so, help would be greatly appreciated. Thanks!
Here the full code for the example:
#include <AmazonIOTClient.h>
#include <Esp8266AWSImplementations.h>
#include <AWSFoundationalTypes.h>
#include "keys.h"
const int sleepTimeS = 30;
void printWiFiData();
void printCurrentNetwork();
void publish(const char *topic, String data);
void publishToAWS();
void setup() {
Serial.begin(9600);
Serial.println("Started!");
publishToAWS();
ESP.deepSleep(sleepTimeS * 1000000);
}
void loop() {
}
void printWiFiData() {
// IP address
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
// MAC address
byte mac[6];
WiFi.macAddress(mac);
Serial.print("MAC address: ");
Serial.print(mac[5], HEX);
Serial.print(":");
Serial.print(mac[4], HEX);
Serial.print(":");
Serial.print(mac[3], HEX);
Serial.print(":");
Serial.print(mac[2], HEX);
Serial.print(":");
Serial.print(mac[1], HEX);
Serial.print(":");
Serial.println(mac[0], HEX);
}
void printCurrentNetwork() {
// SSID
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// signal strength:
Serial.print("signal strength (RSSI): ");
Serial.println(WiFi.RSSI());
}
void publish(const char *topic, String data) {
AmazonIOTClient iotClient;
ActionError actionError;
Esp8266HttpClient httpClient;
Esp8266DateTimeProvider dateTimeProvider;
Serial.println();
Serial.print("Connecting to ");
Serial.print(wifiSsid);
Serial.println("...");
WiFi.begin(wifiSsid, wifiPwd);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(50);
}
Serial.println("");
Serial.println("WiFi connected");
printCurrentNetwork();
printWiFiData();
delay(50);
Serial.println("Initializing IoT client...");
iotClient.setAWSRegion(awsIotRegion);
iotClient.setAWSEndpoint(awsIotEndpoint);
iotClient.setAWSDomain(awsIotDomain);
iotClient.setAWSPath("/things/my-thing/shadow");
iotClient.setAWSKeyID(awsKeyID);
iotClient.setAWSSecretKey(awsSecKey);
iotClient.setHttpClient(&httpClient);
iotClient.setDateTimeProvider(&dateTimeProvider);
delay(50);
Serial.println("Updating thing shadow...");
MinimalString shadow = ("{\"state\":{\"reported\":{\"text\":" + data + "}}}").c_str();
char* result = iotClient.update_shadow(shadow, actionError);
Serial.print("result: ");
Serial.println(result);
}
void publishToAWS() {
Serial.println("Publishing to AWS IoT Broker");
publish("my-thing/text", "Hello World!");
}
keys.cpp file:
#include "keys.h"
// AWS User Credentials
const char* awsKeyID = "XXXXXXXXXXXXXXXXXXXX";
const char* awsSecKey = "X1xxx23xxxxXXXX34XXxxxxX56xXxxxxxxXx789x";
// AWS IoT
const char* awsIotRegion = "eu-central-1";
const char* awsIotEndpoint = "xxxxxxxxxxxxxx";
const char* awsIotDomain = "iot.eu-central-1.amazonaws.com";
// Init and connect WiFi to local WLAN
char* wifiSsid = "mySSID";
char* wifiPwd = "password";
I can finally contribute something :)
I got this very same example working a few days ago. However I used the same library just a different branch iot-get-shadow-and-cleanup. I don't recall having to make any changes as the one you mentioned:
this->awsService = "iotdata"; to this->awsService = "execute-api";
Here are the correct settings for your AWS endpoint that goes into keys.cpp
awsIotRegion = "us-east-1";
awsIotEndpoint = "amazonaws.com";
awsIotDomain = "axxxxs2pxxxrlx.iot.us-east-1.amazonaws.com";`
Also add delete[] result; to the end of the publish() to save some precious heap space.
I would recommend using the iot-get-shadow-and-cleanup branch since it has fixes for memory leaks.
I made one more change to resolve all issues with running out of heap space when updating the shadow continiously. In AWSClient4.cpp I changed // delete[] server; to delete[] data; - I am not 100% sure if this was necessary but combined with the addition of delete[] result; I was able to update the shadown every minute continuously for an hour without loosing any heap.
Hope this helps.
Related
I have a question concerning the Arduino MKRGSM 1400 and MQTT.
I use the code below to connect my MKRGSM to the internet via a SIM-card, then connect it to a HiveMQ-broker I have installed on Docker. Even though the code is compiled without any errors, once I upload it to my board, it crashes. Once it has crashed, I have to reset my board entirely. I've tried this code with the Arduino IDE and Platform.io on VS Code, both give the same result.
Before I put in the MQTT-connection, the board connected successfully to the internet and the DHT11-sensor was able to read humidity and temperature values without problems.
I'm not great with Arduino and this is the first time I'm trying to use MQTT myself.
Does anyone know why the code not only doesn't work, but also makes my board crash?
Thanks in advance!
//Includes
#include <PubSubClient.h>
#include <MKRGSM.h>
#include "DHT.h"
#include <Adafruit_Sensor.h>
//Var declaration
//SIM-internet connection
GSMClient net;
GPRS gprs;
GSM gsmAccess;
const char pin[] = "my pin";
const char apn[] = "my apn";
const char login[] = "my login";
const char password[] = "my password";
//MQTT connection
PubSubClient client;
const String serialNumber = "1";
const String mqtt_server = "server_ip";
const String topic = "/prototype/" + serialNumber;
//DHT sensor PIN declaration
#define DHTPIN 2 //DHT is pinned on 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
void connect() {
//SIM not connected
bool connected = false;
Serial.print("Connecting to cellular network.");
//SIM connecting
while (!connected) {
if ((gsmAccess.begin(pin) == GSM_READY) &&
(gprs.attachGPRS(apn, login, password) == GPRS_READY)) {
//SIM connected
connected = true;
Serial.print("Connected to cellular network.");
}
else {
//If SIM doesn't connect
Serial.print(".");
delay(1000);
}
}
}
void setup() {
Serial.begin(9600);
//Connect to Docker MQTT
client.setServer(mqtt_server.c_str(), 8086);
client.connect(serialNumber.c_str());
Serial.print("MQTT connection state: ");
Serial.println(client.state());
//Start DHT 11
dht.begin();
}
void loop() {
delay(10000);
//Get DHT values
float humidty = dht.readHumidity();
float temperature = dht.readTemperature();
//Create JSON out of values and send it.
const String json = "{\"temperature\": " + String(temperature, 2) + ", \"humidity\": " + String(humidty) + " }";
Serial.println(json);
client.publish(topic.c_str(), json.c_str());
//Check if MQTT connection is holding.
Serial.print("MQTT connection state: ");
Serial.println(client.state());
//Reconnect if MQTT connection is lost.
if (!client.connected()) {
Serial.println("MQTT disconnected! Trying reconnect.");
client.connect("whatever");
}
}
As hashed out in the comments
You never called the connect() function so the GSM network was never setup.
You then probably need to use the GSMClient to initialise the PubSubClient so it knows how to access the network.
I am using PubSubClient library to subscribe to a server using a nodemcu. I tested the code using cloudMQTT and MQTTlens and it worked fine. In addition to that, I used MQTTlens to check mqtt connection with my pc. In there, I did not specify username and password (I kept blank) and it worked just fine. When I want to connect for a public server (ex: "tcp://11.111.111.111"), does not connect.
code for nodemcu
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
const char* ssid = "*****";
const char* password = "****";
const char* mqttServer = "****";
const int mqttPort = 1883;
WiFiClient espClient;
PubSubClient client(espClient);
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
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")) {
Serial.println("connected");
} else {
Serial.print("failed with state ");
Serial.print(client.state());
delay(2000);
}
}
client.publish("topic1", "Hello from ESP8266_tester1");
client.subscribe("topic1");
}
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();
}
the result from the serial monitor
Any suggestion is welcome
If you genuinely don't require a username and password then don't use the connect function that expects them:
...
if (client.connect("ESP8266Client")) {
...
I see you are using a fairly generic client id - ESP8266Client. Remember that all clients connecting to a broker must have a unique client id. If you depoyed this sketch to two different devices they would not both be able to connect at the same time.
The problem was with the ip I have provided. IP does not require "tcp://" part. After removing that, the code worked well.
I'm attempting to connect my Feather Huzzah to a local MQTT server but the program keeps blowing up and throwing a stack trace. When I attempt to decode the stack trace it's just empty, more frequently I only get part of the stack trace. Here's the code that I'm running, most of it is pretty similar to the pub/sub client example code for Arduino. I've tried erasing the flash on the device, that didn't seem to help.
Even stranger is that it worked once, but as soon as I tried it again adding the callback the code stopped working and blows up. If I try removing the callback nothing changes. I've tried stripping out a lot of the code just to see if I can get a consistent connection to MQTT, but that doesn't seem to be working either. The MQTT server is the latest Mosquitto from Ubuntu 18.04.
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <PubSubClient.h>
const char* ssid = "xxxxxxxx";
const char* password = "xxxxxxxxx";
const int hallPin = 14;
const int ledPin = 0;
const char* mqtt_server = "mosquitto.localdomain";
long lastMsg = 0;
char msg[100];
int value = 0;
int hallState = 0;
WiFiClient espClient;
PubSubClient client(espClient);
WiFiUDP ntpUDP;
// By default 'time.nist.gov' is used with 60 seconds update interval and
// no offset
NTPClient timeClient(ntpUDP);
// Setup and connect to the wifi
void setup_wifi() {
delay(100);
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());
Serial.println("Gateway: ");
Serial.println(WiFi.gatewayIP());
}
//Reconnect to the MQTT broker
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 (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("/homeassistant/devices/doorbell", "hello world");
// ... and resubscribe
client.subscribe("/homeassistant/doorbell/receiver");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
//Process messages incoming from the broker
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
}
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(hallPin, INPUT);
Serial.begin(115200);
setup_wifi();
timeClient.begin();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (WiFi.status() != WL_CONNECTED) {
setup_wifi();
}
if (!client.connected()) {
reconnect();
}
hallState = digitalRead(hallPin);
if (hallState == LOW) {
digitalWrite(ledPin, HIGH);
generateAndSendMessage();
delay(1000); //Add in a delay so it doesn't send messages extremely rapidly
} else {
digitalWrite(ledPin, LOW);
}
}
void generateAndSendMessage() {
timeClient.update();
StaticJsonBuffer<100> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["sensor"] = "doorbell";
root["time"] = timeClient.getEpochTime();
root["value"] = 1;
root.printTo(msg);
Serial.println(msg);
client.publish("/homeassistant/devices/doorbell", msg);
}
Looking at the generateAndSendMessage function, I believe you are having an issue due to the size of the MQTT buffer.
The MQTT buffer is by default set to 128 bytes. This includes the length of the channel name along with the message.
The length of you channel is 32 bytes, and the json buffer you used to make the message is 100 bytes long. So you might just be exceeding the 128 byte mark.
Just declare this before including the PubSubClient.h
#define MQTT_MAX_PACKET_SIZE 200
This macro defines the buffer size of the PubSubClient to 200. You can change it to whatever you believe is required.
I hope this helps.
I have programmed to my ESP8266 and subscribed one topic to keep listening messages. This is my graphical view of injecting message to IBM Iot node.
This is my settings of inject view
This is my settings of IBM Iot node.
Here are my logs at Serial Monitor, it is connected and subscribed to cmd channel
So far so good, When I am trying to inject a message to my IBM Iot node then it is not publishing a message, as it is not reaching on serial monitor and no log on debug view. here you can see
Here is source code:
#include <ESP8266WiFi.h>
#include <PubSubClient.h> // https://github.com/knolleary/pubsubclient/releases/tag/v2.3
const char* ssid = "shiv";
const char* password = "manmohan#12345";
#define ORG "2kafk4"
#define DEVICE_TYPE "ESP8266"
#define DEVICE_ID "5CCF7FEED6F0"
#define TOKEN "opKF7v3#8jRM*mGkb_"
char server[] = ORG ".messaging.internetofthings.ibmcloud.com";
char topic[] = "iot-2/cmd/test/fmt/String";
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) {
Serial.print("callback invoked for topic: "); Serial.println(topic);
for (int i = 0; i < payloadLength; i++) {
Serial.print((char)payload[i]);
}
}
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");
}
}
I tried to check cloud foundry logs using cf command, here it is https://pastebin.com/dfMaS1Gd
Can anyone hint me what I am doing wrong ? Thanks in advance.
Confirm the device type is correctly specified in your node configuration. Currently the screenshot show 0.16.2 which doesn't seem to match the device type you registered and what is specified in your code.
I’m having some problem with a home automation project of mine. I bought a nodeMCU v3 from aliexpress that i want to control my blinds with.
This is the code I’m using on it. I use the Arduino IDE to push this code in to the nodeMCU.
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <SimpleTimer.h>
// MQTT Server
const char* ssid = "****";
const char* password = "****";
const char* mqtt_server = "****";
char message_buff[100];
int photoValue = 0;
int rainValue = 0;
int photo = A0;
int rain = D6;
int relayUp = D7;
int relayDown= D8;
long interval = 10000;
long previousMillis = 0;
WiFiClient espClient;
PubSubClient client(espClient);
void setup_wifi() {
delay(10);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
}
void setup() {
pinMode(photo, INPUT);
pinMode(rain, INPUT);
pinMode(relayUp, OUTPUT);
pinMode(relayDown, OUTPUT);
digitalWrite(relayUp ,LOW);
digitalWrite(relayDown, LOW);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
if (client.connect("ESP8266Client")) {
client.subscribe("home/relayBlinds");
} else {
delay(5000);
}
}
}
void loop() {
if (!client.connected()) {
// Connect (or reconnect) to mqtt broker on the openhab server
reconnect();
}
// Read Photo- and Rain-sensors
photoValue = analogRead(photo);
rainValue = analogRead(rain);
// publish Temperature reading every 10 seconds
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
// publish Photo
String pubStringPhoto = String(photoValue);
pubStringPhoto.toCharArray(message_buff, pubStringPhoto.length()+1);
client.publish("home/photo", message_buff);
// publish Rain
String pubStringRain = String(rainValue);
pubStringRain.toCharArray(message_buff, pubStringRain.length()+1);
client.publish("home/rain", message_buff);
}
client.loop();
}
void callback(char* topic, byte* payload, unsigned int length) {
// MQTT inbound Messaging
int i = 0;
// create character buffer with ending null terminator (string)
for(i=0; i<length; i++) {
message_buff[i] = payload[i];
}
message_buff[i] = '\0';
String msgString = String(message_buff);
if (msgString == "BLINDSUP") {
digitalWrite(relayUp ,HIGH);
delay(5000);
digitalWrite(relayUp ,LOW);
} else if (msgString == "BLINDSDOWN") {
digitalWrite(relayDown ,HIGH);
delay(5000);
digitalWrite(relayDown ,LOW);
}
}
The plan was to have a Raspberry Pi with openHAB as a controller. I have used several guides to setup mosquitto and openHAB and i always get the same result.
So this is what happens: the nodeMCU connects to my Wifi and publishes both the rain and photo values. I can read them in the openHAB GUI without problems.
When i press the activation button in openHAB to publish BLINDSUP or BLINDSDOWN the messages arrives without any problems and i can see the message on my mosquitto terminal. Now is when the unexpected result starts happening. The same message gets delivered multiple times to my nodeMCU without it showing up in the mosquitto terminal.
I have been trying to find out why it would act this way and I think it is because the line:
if (!client.connected()) {
is false and the nodeMCU reconnects and gets the same message somehow. But it is always the first message. If I send BLINDSUP and then BLINDSDOWN it will only register BLINDSUP forever.
I'm really out of ideas how to fix this and would appreciate any help, thanks.
URL to the nodeMCU if that helps anyhow: nodeMCU
Try connecting to MQTT broker with a clean session. Probably you published the topic with the retain flag set to true.
If you do like this, the broker will deliver the last retained message when the nodeMCU connects to the broker and subscribes to the retained topic.