Отправка POST запроса от ардуино на web server

kirsanownic
Offline
Зарегистрирован: 13.02.2018

Привет! Ребят, нужна помощь с отправкой POST запроса, с отправкой GET сложностей не возникло, но POST запрос делается чуть по - другому, прошу помочь, как он должен выглядеть?

Вот, как выглядит рабочий get запрос, переделайте под post, пожалуйста. Отправка 2 переменных на сервак http://192.168.1.68:3000/

void sendData(float t, float h) {
  client.connect(server, 80);
  client.print("t=");
  client.print(t);
  client.print("&");
  client.print("h=");
  client.print(h);
  client.println(" HTTP/1.1");
  client.print( "Host: " );
  client.println(server);
  client.println( "Connection: close" );
  client.println();
  client.println();
  client.stop();
  client.flush();
}

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Почитать про формат запросов HTTP - не судьба? Уж если взялись за формирование запросов вручную - почитайте хотя бы основы. Первое - вместо GET для post-запроса надо написать POST. Второе - никаких http:// в строке URI после метода, только относительный адрес, в вашем случае /measurements. Третье - в заголовке Host - никаких http:// - там просто адрес хоста. Четвёртое - для POST-запроса данные запроса - идут после двух переводов строки, в теле запроса, в вашем случае - их надо писать сразу перед строчкой client.stop.

Но лучше всего - ознакомиться с HTTP, хотя бы рамочно.

kirsanownic
Offline
Зарегистрирован: 13.02.2018
Вот так?
 
 
#include <SPI.h>
#include <Ethernet.h>
#include "DHT.h"
 
//Константы
#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
 
byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // Мак адрес
 
EthernetClient client;
 
//Переменные
unsigned long int timeConn = millis();      // Частота отправки данных о t/h на сервер
float h;                                    // Значение температуры
float t;                                    // Значение влажности
char server[] = "192.168.1.68:3000";
 
/*--------------------------------------------------------------
 Необходимые настройки
 --------------------------------------------------------------*/
void setup()
{
  //Старт
  Serial.begin(9600);
  Ethernet.begin(mac);
  dht.begin();
}
/*--------------------------------------------------------------
 Основное тело программы
 --------------------------------------------------------------*/
void loop()
{
  h = dht.readHumidity();
  t = dht.readTemperature();
  if (millis() - timeConn > 2000) {
    sendData(t,h);
    timeConn = millis();
    Serial.println("CONNECT SERVER: Send temp/hum");
  }
}
/*--------------------------------------------------------------
 Функция отправляет данные о температуре и влажности на 
 WEB сервер.
 --------------------------------------------------------------*/
void sendData(float t, float h) {
  client.connect(server, 80);
  client.print( "POST /measurements");
  client.println(" HTTP/1.1");
  client.print( "Host: " );
  client.println(server);
  
  client.println();
  client.println();
  client.print("t=");
  client.print(t);
  client.print("&");
  client.print("h=");
  client.print(h);
  client.println( "Connection: close" );
  client.stop();
  client.flush();
}
DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Не хватает правильного заголовка Content-Type. Вы прочитаете про HTTP или так и будете выманивать по строчке? Подсказка - методы кодирования тела сообщения при отправке запроса POST - бывают разные. Ваш - application/x-www-form-urlencoded

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Вангую, что следующим вопросом будет "почему данные неправильно воспринимаются сервером". Отвечу заранее: читать тут, как вариант - https://www.w3schools.com/tags/ref_urlencode.asp

kirsanownic
Offline
Зарегистрирован: 13.02.2018

Прочитал пару статей про post запросы, все равно не могу заставить работать, помогите!) 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Что именно непонятно из написанного мной выше? Ок, задам вопрос по-другому: приведи мне пожалуйста текст POST-запроса, который ты считаешь правильным, и который надо послать на сервер. Не код для ардуины - а именно текст запроса, типа такого (\r\n - символизируют переводы строки):

POST /uri HTTP/1.1\r\n

Host: blabla.com\r\n

Content-Length: 1234\r\n\r\n

Content-Type: application/x-www-form-urlencoded\r\n

Connection: close\r\n\r\n

name1=value1&name2=value2

То, что я привёл выше - валидный POST-запрос, за исключением неправильно рассчитанного Content-Length.

kirsanownic
Offline
Зарегистрирован: 13.02.2018

У меня вот так, нет \r\n\r\n, они все равно нужны, если у меня client.println?

POST /measurements HTTP/1.1
Host: 192.168.1.68:3000
content-type: application/x-www-form-urlencoded
Connection: close
t=10&h=20

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

У вас неправильный запрос. Во-первых, нет Content-Length. Во-вторых - нет двух переводов строки между последним заголовком и данными. В-третьих - вот тут есть пример, изучайте: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST

whitediver
Offline
Зарегистрирован: 15.05.2019

DIYMan пишет:

POST /uri HTTP/1.1\r\n

Host: blabla.com\r\n

Content-Length: 1234\r\n\r\n

Content-Type: application/x-www-form-urlencoded\r\n

Connection: close\r\n\r\n

name1=value1&name2=value2

То, что я привёл выше - валидный POST-запрос, за исключением неправильно рассчитанного Content-Length.

Здравствуйте, подскажите кто-нибудь, а почему коннект закрывается до появления в запросе аргументов? Оо

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

whitediver пишет:

Здравствуйте, подскажите кто-нибудь, а почему коннект закрывается до появления в запросе аргументов? Оо

а скетч есть? в котором закрывается коннект

whitediver
Offline
Зарегистрирован: 15.05.2019

Скетча нет, я процитировал пост гуру, который выше пмогал человеку.

Сам сейчас разбираюсь в этом вопросе, попал вот в руки ардуино, изучаю вопрос, так сказать.

У меня в скетче это сделано вот так:

if (client.connect("192.168.188.10",80)) {
    Serial.println("TRUE");
    client.println("POST /php/test.php HTTP/1.1"); 
    client.println("Host: 192.168.188.10");
    client.println("Content-Length: 8");  
    client.println("Content-Type: application/x-www-form-urlencoded");  
    client.println(); 
    client.print("x=");
    client.println(fill);
//    client.println("Connection: close");
//    client.stop();
  } 
 else
  Serial.println("FALSE");

  if (client.connected()) { 
    client.stop(); 
  }

И в принципе всё работает, test.php получает параметр "х"

Единственное что мне не понятно, почему-то $_POST['x'] получается текстовой переменной, echo выводить "111.11", когда я раньше баловался с PHP при передаче числовых значений на выходе я и получал числовые значения, а тут почему-то строка...

Получается перед дальнейшим использованием мне придётся её сначала в число как-то перегнать =\

negavoid
Offline
Зарегистрирован: 09.07.2016

Connection: close означает, что сервер после ответа на запрос закроет соединение, и не будет поддерживать его keep-alive.

В Host: можно писать не ip, а домен, на одном ip может быть много виртуальных хостов.

content-length: 8 означает 8 байт полезной нагрузки, включая "x=" - стало быть, после него на сервер должно уйти ещё 6 байт. "111.11" похожи на 6 байт.

whitediver
Offline
Зарегистрирован: 15.05.2019

меня 111.11 вполне устраивает, это как раз то что мне нужно, только оно на сервер не как число с двумя знаками после точки приходит а прям вот в таком виде => "111.11"

Это нормально?

 

echo $_POST['x']

// Выдаёт мне на страницу:
// "111.11"

 

negavoid
Offline
Зарегистрирован: 09.07.2016

Что отправляете - то и приходит, это вполне нормально.

echo intval( $_POST["x"] );

 

whitediver
Offline
Зарегистрирован: 15.05.2019

Я отправляю х=111.11, а не х="111.11"

Как отправить число, чтобы получить число, подскажете ?)

UPD: Всё разобрался... у меня fill раньше формаитровался в строку дополненную всяким антуражем, я антураж убрал, а стринг на инт забыл поменять.

b707
Offline
Зарегистрирован: 26.05.2017

whitediver пишет:

Я отправляю х=111.11, а не х="111.11"

нет, вы отправляете именно "111.11". Вы ползуетесь командой print. а она превращает ваше число 111.11 в строку "111.11"

Вообще на сервере получить из этого число не должно быть проблемой, например на Апаше сервер сам парсит парметры POST или GET запроса

whitediver
Offline
Зарегистрирован: 15.05.2019

Да, выше уже уточнил пост, что оказывается я отправляю стринг, а не инт, это раз.

А два, intval() помогло :)

У меня пхп на серверер к IIS прикручен.

negavoid
Offline
Зарегистрирован: 09.07.2016

Php всё равно, он получает из запроса байты, а не числа или строки, может представить их для echo, как строку. А уже как дальше интерпретировать полученные данные - это ваше дело, а не php.

>> IIS

Хозяин-барин, конечно :) ну, или может, египтянин :))

 

whitediver
Offline
Зарегистрирован: 15.05.2019

Спасибо за помощь, всё что пока хотел реализовать вышло.

 

Редко обращаюсь к программированию, по этому за время перерывов многое успеваю забыть, в плане операторов, приходится неистово гуглить )))

b707
Offline
Зарегистрирован: 26.05.2017

negavoid пишет:

Php всё равно, он получает из запроса байты, а не числа или строки, может представить их для echo, как строку. А уже как дальше интерпретировать полученные данные - это ваше дело, а не php.

насколько я помню, в php динамические типы данных. то есть для него 111.11 и "111.11" - в принципе одно и тоже. Если с перлом не путаю...

negavoid
Offline
Зарегистрирован: 09.07.2016

Да, динамические. Начиная с 7, начали прикручивать и статическую типизацию (гыы :), и можно ещё раньше было начать ей пользоваться через phpdoc.

whitediver
Offline
Зарегистрирован: 15.05.2019

negavoid пишет:

>> IIS

Хозяин-барин, конечно :) ну, или может, египтянин :))

 

Этож не продакшн... у меня 1С через web на рабочей машине крутится, что бы лишнего не ставить, раз уж 80 порт занят, прикрутил к IIS php, работает... так же и БД на MSSQL работает, пришлось драйвер от мелкомягких к php прицепить, кривожопая хрень какая-то sqlsrv_num_rows() только через задницу работает, наверное и всё остальное тоже... но мне надо пока только select да insert... 

Макет одного порграммно технического комплекса ваяю, людям показать :)

В "Продакшн" потом всё по взрослому писаться будет... (наверное :D)

vlad072
Offline
Зарегистрирован: 01.08.2017

что используете для коннекта с сервером? Подавляющее большиство модемов из коробки "умеют" HTTP. FTP, SMTP/POP/IMAP и ещё много страшный слов )) Почитайте мануал к своему

whitediver
Offline
Зарегистрирован: 15.05.2019

Не знаю, не смотрел, библеотеку юзаю ESP8266WiFi.h

Метод WiFiConnect.

Всё остальное так же как при использовании Ethernet.h POST HTTP.... бла бла бла )

p-a-h-a
Offline
Зарегистрирован: 17.01.2019

На narodmon.ru так делал:

void POST_Narodmon() {
  HTTPClient http;
  http.begin("http://narodmon.ru/api");// странно, но форум меняет адрес. Должно быт ("HTTP://народмон.ру/апиай") английскими естестно
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");

  StaticJsonDocument<400> doc; // Создаем и наполняем json для последующей отправки на сервер
  doc["cmd"] = "sensorsValues";
  doc["sensors"] = SensorID;
  doc["uuid"] = uuid;
  doc["api_key"] = api_key;

  http.POST(doc.as<String>());// Json запрос на сервер
  if (debug) Serial.println(doc.as<String>());
  doc.clear();
  DynamicJsonDocument Answer(1532);                                 // Инициализируем буфер под JSON // Эта константа определяет размер буфера под содержимое JSON 8ми датчиков (расчитывается тут https://arduinojson.org/v5/assistant/)
  deserializeJson(Answer, http.getString());                     // Парсим JSON-содержимое ответа сервера
  http.end();
  //Serial.println(Answer.as<String>()); //Выводим содержимое что прислал сервер
  if (debug) {
    serializeJsonPretty(Answer, Serial);  //Выводим содержимое что прислал сервер красиво по строчкам
    Serial.println();
  }
Serial.println("Время передачи " + Answer["sensors"][0]["value"].as<String>() + " сек");
Serial.println("Влажность " + Answer["sensors"][1]["value"].as<String>() + " %");
Serial.println("Атмосферное давление " + Answer["sensors"][2]["value"].as<String>() + " мм рт. ст.");
Serial.println("Температура на улице " + Answer["sensors"][4]["value"].as<String>() + " градусов цельсия");
Serial.println("Напряжение аккумулятора " + Answer["sensors"][6]["value"].as<String>() + " В");
Serial.println("Уровень сигнала WI-FI " + Answer["sensors"][7]["value"].as<String>() + "%");

  Answer.clear();
  Serial.println();



}

 

СовсемЗелёный
Offline
Зарегистрирован: 06.10.2021

День добрый господа, задача была такая, на входы ардуинки приходит сигнал, после этого ардуино должна сделать пост запрос на айпи адрес. Из комплектующих arduino uno, hr911105a.
Как-то совсем не выходит сделать пост запрос, чего-то я не понимаю, пробовал библиотеку ethercard.

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

СовсемЗелёный пишет:
Из комплектующих arduino uno, hr911105a.

Да, с таким комплектом сложно POST запрос будет отправить. ))

https://www.chipdip.ru/product/hr911105a

 

СовсемЗелёный
Offline
Зарегистрирован: 06.10.2021

ENC28J60 Enternet HR911105A
Обшибся)

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

Ну теперь желательно выложить Ваш код (в соответствии с правилами форума), где вы пробовали.

СовсемЗелёный
Offline
Зарегистрирован: 06.10.2021

Пробовал с этим работать, но не совсем понял, как свои переменные, если их так можно назвать, вставить в этот код, также есть ошибка относительно кода, хоть убей, софту не нравится Ethernet

 

========================================

http://arduino.ru/forum/obshchii/vstavka-programmnogo-koda-v-temukommentarii

 

 

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018
СовсемЗелёный
Offline
Зарегистрирован: 06.10.2021

Буду исправляться, увы, но я и правда совсем зелёный, скоро подкорректирую вопрос и сделаю по правилам и обычаям :)

sadman41
Offline
Зарегистрирован: 19.10.2016

UIPEthernet оригинальный будет попроще. От Нортберта который.

СовсемЗелёный
Offline
Зарегистрирован: 06.10.2021

Только вот понятия не имею, как работать с этой библиотекой

sadman41
Offline
Зарегистрирован: 19.10.2016

Так же, как со стоковой Ethernet из Arduino IDE.

СовсемЗелёный
Offline
Зарегистрирован: 06.10.2021

Я тут немного продвинулся, но опять воткнулся в землю, адрес по dhcp получает, но запрос до адресата не доходит, в чём может быть дело?

#include <EtherCard.h>

static byte mymac[] = {0x74,0x69,0x69,0x2D,0x30,0x31};
byte Ethernet::buffer[600];
byte session_id;
Stash stash;

const char website[] PROGMEM = "192.168.55.104";
const char authorization[] PROGMEM = "YWRtaW46TdSaWlOaXU=";

void setup () {
 
  Serial.begin(57600);
  Serial.println("Basic authentication demo");
  Serial.println();
 
  if (!ether.begin(sizeof Ethernet::buffer, mymac, 10)) {
    Serial.println( "Failed to access Ethernet controller");
    while(1); 
  } else Serial.println("Ethernet controller initialized");
  Serial.println();
 
  if (!ether.dhcpSetup()) {
    Serial.println("Failed to get configuration from DHCP");
    while(1);
  } else Serial.println("DHCP configuration done:"); 
 
  ether.printIp("IP Address:\t", ether.myip);
  ether.printIp("Netmask:\t", ether.netmask);
  ether.printIp("Gateway:\t", ether.gwip);
  
 
  
  Stash::prepare(PSTR("GET /cgi-bin/ptz.cgi?action=start&channel=0&code=GotoPreset&arg1=0&arg2=7&arg3=0 HTTP/1.0" "\r\n"
    "Host: $F" "\r\n" 
    "Authorization: Basic $F" "\r\n"
    "\r\n"), website , authorization);
  
  session_id = ether.tcpSend();
  Serial.println("Request sent");
}
  
void loop() {

 
}

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Из чего следует "не доходит?"
Камере много чего может не нравится и она не обязана отвечать на все подряд.
Сделайте запрос на локальный XAMPP, убедитесь в этом.

СовсемЗелёный
Offline
Зарегистрирован: 06.10.2021

то бишь, ошибка в формулировке запроса, так?
есть смысл через wireshark пробовать смотреть?

sadman41
Offline
Зарегистрирован: 19.10.2016

Всегда есть смысл зацепить реальный обмен или фидлером или вайршарком.