Receive sensor data, publish on webpage - http.POST(jsonData) - http

I'm new to programming a php page, so I may ask too much, hope you bear out with me.
My case:
I have an Arduino Bee Hive monitoring system that sends live data, temperature and weight.
On my LAN I have a web server on my Synology NAS running php 7.4
I think this code is based websocket,not shure.
Arduino device has IP 192.168.0.52
Server IP 192.168.0.5, http port 9978, https not enabled
On web server no values are seen, if received I dont know.
Code for Arduino sender side is running and also state that "Data sent successfully":
#include <HTTPClient.h>
#include <WiFi.h>
#include <Ethernet.h>
const char* host = "192.168.0.5"; //web server synology NAS
const int port = 9978; // http port Synology
const char* ssid = "nettUser";
const char* password = "nettPass";
//web login
char username[] = "serverUser";
char userpassword[] = "serverPass";
void loop() {
// Read sensor values and store in temperature and humidity
// Read the temperature and weight values
float temperature = 25.0; // for php test purpose, fixed values
float weight = 50.0;
// Create a JSON object to store the data
String jsonData = "{\"temperature\":" + String(temperature) + ",\"weight\":" + String(weight) + "}";
// Create an instance of the HTTPClient class
HTTPClient http;
// Make a POST request to the server
http.begin("http://" + String(host) + ":" + String(port));
http.addHeader("Content-Type", "application/json");
http.setAuthorization(username, userpassword);
int httpCode = http.POST(jsonData);
// Check the response code
if (httpCode > 0) {
Serial.println("Data sent successfully");
} else {
Serial.println("Error sending data");
}
// Close the connection
http.end();
Serial.print("[WiFi] IP address: ");
Serial.println(WiFi.localIP());
Serial.println(temperature_f);
Serial.println(humidity_f);
delay(5000);
}
}
Arduino output
Server side:
Code I found on internet, with some modifications
saved as index.php
<html>
<head>
<script>
function updateData() {
const xhr = new XMLHttpRequest();
xhr.open("GET", "http://192.168.0.52:80");
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
const data = JSON.parse(xhr.responseText);
document.getElementById("temperature").innerHTML = data.temperature;
document.getElementById("weight").innerHTML = data.weight;
} else {
console.error(xhr.statusText);
}
}
};
xhr.send();
}
setInterval(updateData, 1000);
</script>
</head>
<body>
<h1>HiveMon - v 1</h3>
<h3>Temperature: <span id="temperature"></span>℃</h3>
<h3>Weight: <span id="weight"></span>%</h3>
</body>
</html>
Web page
Code above is running now.
I have not tried much, but I tested in web server code to enter web server ip 192.168.0.5 instead of 192.168.0.52 with no help

I guess you are trying to get a "live" update of your sensor's data on your web page, right?
If so, I may suggest implementing the following pattern:
From the above, you are only missing the request handler!
This mechanism is straightforward; when Arduino sends a request, it tells the request handler to save the data temporarily into the data handler and any time the web app pulls data, the request handler responds with the data previously submitted by Arduino.
So following is the code that implements this
request_handler.php (Created at your root folder)
<?php
$post_data = file_get_contents("php://input"); //as you send data as raw json
if ($post_data) { //when request comes from arduino, you will have post data
$json_data = json_encode($post_data);
if (file_put_contents("data.txt", $json_data)) {
echo "Ok";
} else {
http_response_code(400); //when data did not save
echo "Bad Request";
}
} else { //when the web app make a call to the request handler
$previous_data = file_get_contents("data.txt");
echo $previous_data;
}
And slightly change your arduino code to :
#include <HTTPClient.h>
#include <WiFi.h>
#include <Ethernet.h>
const char* host = "192.168.0.5"; //web server synology NAS
const int port = 9978; // http port Synology
const char* ssid = "nettUser";
const char* password = "nettPass";
//web login
char username[] = "serverUser";
char userpassword[] = "serverPass";
void loop() {
// Read sensor values and store in temperature and humidity
// Read the temperature and weight values
float temperature = 25.0; // for php test purpose, fixed values
float weight = 50.0;
// Create a JSON object to store the data
String jsonData = "{\"temperature\":" + String(temperature) + ",\"weight\":" + String(weight) + "}";
// Create an instance of the HTTPClient class
HTTPClient http;
// Make a POST request to the server
http.begin("http://" + String(host) + ":" + String(port) + "/request_handler.php");
http.addHeader("Content-Type", "application/json");
http.setAuthorization(username, userpassword);
int httpCode = http.POST(jsonData);
// Check the response code
if (httpCode > 0) {
Serial.println("Data sent successfully");
} else {
Serial.println("Error sending data");
}
// Close the connection
http.end();
Serial.print("[WiFi] IP address: ");
Serial.println(WiFi.localIP());
Serial.println(temperature_f);
Serial.println(humidity_f);
delay(5000);
}
}
Finally your index.php
<html>
<head>
<script>
function updateData() {
const xhr = new XMLHttpRequest();
xhr.open("GET", "http://192.168.0.52:80/request_handler.php");
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
const data = JSON.parse(xhr.responseText);
document.getElementById("temperature").innerHTML = data.temperature;
document.getElementById("weight").innerHTML = data.weight;
} else {
console.error(xhr.statusText);
}
}
};
xhr.send();
}
setInterval(updateData, 1000);
</script>
</head>
<body>
<h1>HiveMon - v 1</h3>
<h3>Temperature: <span id="temperature"></span>℃</h3>
<h3>Weight: <span id="weight"></span>%</h3>
</body>
</html>
Hope it helps!

Related

How to receive JSON response from REST API using ESP8266 Arduino framework

I am trying to use Beyond Verbal RST API to post voice sample data over HTTP post method from ESP8266. The first step for the API communication is to get access token using the POST method. You can check the following codes. With this code I am just getting "failed to Post" response on serial output.
#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ESP8266HTTPClient.h>
const char *ssid = "xxxxxx";
const char *pass = "xxxxxx";
String token;
HTTPClient https;
WiFiClientSecure client;
String getRecordID(String stoken);
void setup() {
Serial.begin(115200);
Serial.println("connecting to network..");
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("conntected to network..");
}
void loop() {
String ret;
token = getAccessToken();
delay(2000);
Serial.println(token);
}
String getAccessToken(){
// client.setInsecure();
const char * host = "token.beyondverbal.com";
const uint16_t port = 443;
const char * path = "/token";
StaticJsonBuffer<1000> jb;
String res;
Serial.println("conntecting to server..");
if (https.begin(client, host, port, path)) {
https.addHeader("Content-Type", "x-www-formurlencoded");
int httpsCode = https.POST("grant_type=client_credentials&apiKey=1d0956a4-3deb-431a-b3e0-45f5c371fe99");
if (httpsCode > 0) {
if (httpsCode == HTTP_CODE_OK) {
JsonObject& obj = jb.parseObject(https.getString());
String token = obj["access_token"];
if (obj.success()) {
res = token;
} else {
res = "failed to parse json";
}
}
} else {
res = "failed to Post";
}
} else {
res = "failed to connect to server";
}
https.end();
return res;
}
Check out the guideline documentation and please read the authentication part. I have followed the steps and tried in several ways, but still no luck.
But my API code and others parameter are ok. I have tried API post method from Mozilla Firefox addon and different platform. From everywhere I got the token successfully. But I am still unable to get the token with my code.
Please check and me a solution regarding the issue.
Use these libraries. ESPAsyncTCP, asyncHTTPrequest
then use below code. Code for sample.
#include <ESPAsyncTCP.h>
#include <asyncHTTPrequest.h>
asyncHTTPrequest client;
asyncHTTPrequest client2;
void onClientStateChange(void * arguments, asyncHTTPrequest * aReq, int readyState) {
Serial.println(readyState);
switch (readyState) {
case 0:
// readyStateUnsent // Client created, open not yet called
break;
case 1:
// readyStateOpened // open() has been called, connected
break;
case 2:
// readyStateHdrsRecvd // send() called, response headers available
break;
case 3:
// readyStateLoading // receiving, partial data available
break;
case 4:
// readyStateDone // Request complete, all data available.
#ifdef SERIAL_DEBUG
Serial.println(aReq->responseHTTPcode());
#endif
if (aReq->responseHTTPcode() != 200) {
#ifdef SERIAL_DEBUG
Serial.println("return");
#endif
return;
}
String response = aReq->responseText();
#ifdef SERIAL_DEBUG
Serial.println(response.c_str());
#endif
break;
}
}
void setupClient() {
String URL = "dummy.restapiexample.com/api/v1/create";
client.setTimeout(5);
client.setDebug(false);
client.onReadyStateChange(onClientStateChange);
client.open("POST", URL.c_str());
client.setReqHeader("Content-Type", "application/json");
client.send("{\"name\":\"test\",\"salary\":\"123\",\"age\":\"23\"}");
String URL2 = "jsonplaceholder.typicode.com/users";
client2.setTimeout(5);
client2.setDebug(false);
client2.onReadyStateChange(onClientStateChange);
client2.open("GET", URL2.c_str());
client2.send();
}
Always connect with async client as it will not block your main execution until you will get a response.

Unstable or slow communication between ESP8266 server and web browser client

I am using an ESP8266 Thing Dev board configured as an access point and server to store data from temperature sensors.
The goal is to access this data with an Android application, but for now, the client used is my computer running Chrome.
The sensors provide new temperatures every 250 ms, which are added to a string (JSON formatted).
When the client requests the data, the string is ended (closing JSON structure), and printed on the server.
The client should be able to access up to 2*50 values at a time. However, each time a request is send, either only 2 or 4 values are printed, either the page is not working.
My Arduino code, using ESP8266 and TMP102 libraries for arduino :
#include <ESP8266WiFi.h>
#include <Wire.h>
#include <Ticker.h>
#include "tmp102.h"
#define NB_MAX_TEMP 50
#define MAX_INPUT 20
const byte sensorAddress1 = 0x90; // ADD0 -> GND
const byte sensorAddress2 = 0x92; // ADD0 -> V+
tmp102 *thermometer1 = new tmp102(&Wire);
tmp102 *thermometer2 = new tmp102(&Wire);
// Timer
Ticker ticker;
bool flag = false;
// Wifi
const char WiFiAPPSK[] = "sparkfun"; // Wifi password
WiFiServer server(80);
int count = 0;
String s;
void setupWiFi()
{
WiFi.mode(WIFI_AP);
// Do a little work to get a unique-ish name. Append the
// last two bytes of the MAC (HEX'd) to "ThingDev-":
uint8_t mac[WL_MAC_ADDR_LENGTH];
WiFi.softAPmacAddress(mac);
String macID = String(mac[WL_MAC_ADDR_LENGTH - 2], HEX) +
String(mac[WL_MAC_ADDR_LENGTH - 1], HEX);
macID.toUpperCase();
String AP_NameString = "ThingDev-" + macID;
char AP_NameChar[AP_NameString.length() + 1];
memset(AP_NameChar, 0, AP_NameString.length() + 1);
for (int i = 0; i < AP_NameString.length(); i++)
AP_NameChar[i] = AP_NameString.charAt(i);
WiFi.softAP(AP_NameChar, WiFiAPPSK);
}
void timer_done()
{
flag = true;
}
void acquire()
{
int temp1 = 0, temp2 = 0;
if (thermometer1->readTemp(temp1))
{
// If we're reading pins, print out those values:
// first temp
s += String(temp1 * 0.0625);
}
s += ",";
if (thermometer2->readTemp(temp2))
{
// If we're reading pins, print out those values:
// second temp
s += String(temp2 * 0.0625);
}
return;
}
void setup()
{
Wire.begin(); // start the I2C library
Serial.begin(115200);
thermometer1->init(sensorAddress1);
thermometer2->init(sensorAddress2);
//Set default config.
thermometer1->writeConf(TMP102_DEFAULT_CONF);
thermometer2->writeConf(TMP102_DEFAULT_CONF);
setupWiFi();
server.begin();
// timer every 0.25s
ticker.attach(0.25, timer_done);
}
void loop()
{
// Check if a client has connected
WiFiClient client = server.available();
if (!client) {
return;
}
if (flag) {
flag = false;
int temp1 = 0, temp2 = 0;
if (count == 0) {
// prepare string
s = "HTTP/1.1 200 OK\r\n";
s += "Content-Type: text/html\r\n\r\n";
s += "{temp:[";
}
delay(1);
// add a measurement
s += "[";
acquire();
s += "],";
count += 1;
if (count == NB_MAX_TEMP) {
// Prevent the string to become infinite
count = 0;
s = s.substring(0, s.length() - 1);
s += "]};";
}
}
if (client.available() > 0) {
// Read the first line of the request
String req = client.readStringUntil('\r');
client.flush();
Serial.println(req);
if (req.indexOf("/read") != -1) {
// End the string
s.setCharAt(s.length() - 1, '\0');
s += "]};";
client.print(s);
Serial.println(s);
count = 0;
}
}
delay(1);
Serial.println("Client disconnected");
// The client will actually be disconnected
// when the function returns and 'client' object is detroyed
}
And a sample of what I get on the Serial console (the JSON string is the same I read on the server page) :
GET /read HTTP/1.1
HTTP/1.1 200 OK
Content-Type: text/html
{temp:[[24.00,24.56],[24.00,24.56];
Client disconnected
GET /favicon.ico HTTP/1.1
Client disconnected
GET /read HTTP/1.1
HTTP/1.1 200 OK
Content-Type: text/html
{temp:[[24.00,24.56];
Client disconnected
What am I doing wrong ? Am I using a blocking function ? Are the /favicon.ico requests causing trouble ?
For information, the access point part, and the sensor part of my code have been tested separately and work as expected.
Thanks in advance.

enc28j60 with arduino and local web service

please help
i am trying to use arduino Pro mini with ENC28j60 to get data from my local web service
the URL i used to get the data is (http://192.168.1.5:801/m/Service1.asmx/HelloWorld?tag=01)
when i use this URL in browser it return this result
peter danile,1234567
with arduino
i use this code but i can't get a result
// Demo using DHCP and DNS to perform a web client request.
// 2011-06-08 <jc#wippler.nl> http://opensource.org/licenses/mit-license.php
#include <EtherCard.h>
// ethernet interface mac address, must be unique on the LAN
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[700];
static uint32_t timer;
const char website[] PROGMEM = "192.168.1.5";
//char website[] PROGMEM = "google.com";
// called when the client request is complete
static void my_callback (byte status, word off, word len) {
Serial.println(">>>");
Ethernet::buffer[off+300] = 0;
Serial.print((const char*) Ethernet::buffer + off);
Serial.println("...");
}
void setup () {
Serial.begin(57600);
Serial.println("\n[webClient]");
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println( "Failed to access Ethernet controller");
if (!ether.dhcpSetup())
Serial.println("DHCP failed");
ether.printIp("IP: ", ether.myip);
ether.printIp("GW: ", ether.gwip);
ether.printIp("DNS: ", ether.dnsip);
if (!ether.dnsLookup(website))
Serial.println("DNS failed");
ether.printIp("SRV: ", ether.hisip);
}
void loop () {
ether.packetLoop(ether.packetReceive());
if (millis() > timer) {
timer = millis() + 5000;
Serial.println();
Serial.println(PSTR("/m/Service1.asmx/HelloWorld?"));
Serial.print("<<< REQ ");
ether.hisport = 801;//to access local host
ether.browseUrl(PSTR("/m/Service1.asmx/HelloWorld?"), "tag=01", website, my_callback);
}
}

Need help getting value from html slider on yun to arduino value

My setup: arduino leonardo + yun shield
What I'm trying to accomplish:
Display a temperature via one-wire on html served by yun. Allow user to set goal temperature via slider bar on yun html page and have that set the value of a variable in the function "goaltemp".
Here is my html:
<!DOCTYPE html>
<html>
<head>
<title>AngularJS / Arduino</title>
<meta name="viewport" content="width=device-width">
<script type="text/javascript" src="zepto.min.js"></script>
<script type="text/javascript">
function refresh() {
$('#content').load('/arduino/temperature');
}
var value;
function sendVal() {
$.get('/arduino/goaltemp' + value, function(){
}
);
}
function updateVal(val) {
value = val;
$("#val").text(value);
sendVal();
}
</script>
</head>
<body onload="setInterval(refresh, 2000);">
<span id="content">0</span>
<p>Goal Temperature:
<input type="range" min="0" max="230" onchange="updateVal(this.value);">
<p id="val">0</p>
</p>
</body>
</html>
Here is my arduino sketch:
#include <Bridge.h>
#include <YunServer.h>
#include <YunClient.h>
#include <SevSeg.h>
#include <OneWire.h>
#include <DallasTemperature.h>
//*****Temp Read
//code from http://milesburton.com/Main_Page?title=Dallas_Temperature_Control_Library
//Orange Stripe is PWR: 3-5V,
//White Stripe is GND
//Blue Stripe is data.
// Data wire is plugged into pin 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
//Powerswitch Tail
const int powerPin = A0;
boolean powerOn = false;
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
// Listen on default port 5555, the webserver on the Yún
// will forward there all the HTTP requests for us.
YunServer server;
String startString;
long hits = 0;
void setup() {
//Serial.begin(9600);
// Bridge startup
Bridge.begin();
// Listen for incoming connection only from localhost
// no one from the external network could connect
server.listenOnLocalhost();
server.begin();
// get the time that this sketch started:
Process startTime;
startTime.runShellCommand("date");
while (startTime.available()) {
char c = startTime.read();
startString += c;
}
}
void loop() {
int temp = (sensors.getTempFByIndex(0));
sensors.requestTemperatures(); // Send the command to get temperatures
// Get clients coming from server
YunClient client = server.accept();
// There is a new client?
if (client) {
// read the command
String command = client.readString();
command.trim(); //kill whitespace
Serial.println(command);
// is "temperature" command?
if (command == "temperature") {
// get the time from the server:
Process time;
time.runShellCommand("date");
String timeString = "";
while (time.available()) {
char c = time.read();
timeString += c;
}
Serial.println(timeString);
int sensorValue = analogRead(A1);
// convert the reading to millivolts:
// convert the millivolts to temperature celsius:
// print the temperature:
//client.print("Current time on the Yún: ");
//client.println(timeString);
client.print("<br>Current temperature: ");
client.print(temp);
client.print(" °F");
//client.print("<br>This sketch has been running since ");
//client.print(startString);
client.print("<br>Hits so far: ");
client.print(hits);
}
if (command == "goaltemp") {
int value = client.parseInt();
client.print("<br>The Goal Temperature is ");
client.print(value);
client.print(" °F");
}
// Close connection and free resources.
client.stop();
hits++;
}
delay(50); // Poll every 50ms
}
The temperature reporting currently works great. I cannot, however, figure out how to pass the value of the slider in my html to arduino. Any advice or help would be greatly appreciated!
Have you checked out the example code and documentation here: https://www.arduino.cc/en/Guide/ArduinoYun#toc20? The sample code there covers what you are attempting to do.
Specifically, pay attention to how the code author breaks down the processing of the URL arguments using different functions as so:
void process(YunClient client) {
String command = client.readStringUntil('/');
if (command == "digital") {
digitalCommand(client);
}
if (command == "analog") {
analogCommand(client);
}
if (command == "mode") {
modeCommand(client);
}
}
In each processing function, you can simply do a client.readStringUntil('/') to parse down the tree. Eventually, you will get your goaltemp value.
Hint, you may want to format your URL as /arduino/goaltemp/20 - that will make parsing easier.
Good luck!

ethernet webserver example, client.stop causes lag time issues

Using the ethernet WebServer example code, I've got my arduino to host a website stored on an SD card. The website uses jquery to post the position of the mouse in the webbrowser back to the arduino. I would ultimately like to use this info to control a servo motor, however, the problem I have is that the client.stop line in each iteration of the void loop causes a large lag time in between when the mouse moves and when the arduino gets the information.
Is there a way to make this code only use the execute the stop.client line when the mouse stops moving. So effectively when there no information being sent from the to the arduino via the post method?
Here is my code.
#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
String POST = "";
int count = 0;
const int chipSelect = 4;
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,178,30);
// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
EthernetClient client;
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
Serial.setTimeout(10);
//start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
client.setTimeout(1);
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
//SD card stuff
Serial.print("Initializing SD card...");
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
return;
}
Serial.println("card initialized.");
}
void loop() {
// listen for incoming clients
EthernetClient client = server.available();
if (client) {
Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
String POST = "";
while(client.available()){
c = client.read();
// save the variables somewhere
POST += c;
}
if(POST != ""){
Serial.println(POST);
}
//load html/css/js for website only once
if (count <= 0){
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
//client.println("Refresh: 5"); // refresh the page automatically every 5 sec
client.println();
File dataFile = SD.open("site.txt");
// if the file is available, write to it:
if (dataFile) {
while (dataFile.available()) {
//Serial.write(dataFile.read());
client.write(dataFile.read());
}
dataFile.close();
}
// if the file isn't open, pop up an error:
else {
Serial.println("error opening site.txt");
}
}
//count = 1;
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
if (count == 0){
delay(500);
}
else{
delay(1);
}
count=1;
// close the connection:
client.stop();
Serial.println("client disonnected");
}
}
yes, is possible but realy hard as you have to implement HTTP\1.1, also this will reamin slow as for every mouse position, browser have to send a full HTTP request, arduino read and intepretate it.
Best solution is to use websocket (there are already some serbsocket server lybrary for arduino), once a websocket is setted-up, you have a two way communication exactly like a Serial!

Resources