Как Arduino может сохранять данные из PHP Script?

Я создал скрипт PHP, чтобы получить данные из своей онлайн-базы данных (MySQL), но я не смог передать эту информацию в arduino + Ethernet Shield (используя Ethercard.h).

Все, что я хочу, — это получить все, что мой PHP-скрипт извлекал как вектор строк.

Пример того, что возвращает мой PHP-скрипт:

ABCDF
GHYEJ
JDYDI
HSTSU
PIFYF

Я хочу, чтобы это стало таким в моем Arduino:

char* test = {"ABCDF", "GHYEJ". "JDYDI", "HSTSU", "PIFYF" };

Кто-нибудь может мне помочь с этим?

Редактировать:
Итак, я пробую решение @ frarugi87, но мне не удалось получить DNS. Вот код, который я использую:

#include <enc28j60.h>
#include <EtherCard.h>
#include <net.h>

#define HTTP_HEADER_OFFSET 0

/* Setup for Ethernet Library */
static byte mymac[] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x31 };
static byte myip[] = {192,168,1,58};
static byte gatewayip[] = {192,168,1,1};
static byte dnsip[] = {8,8,8,8}; //Google DNS
const char website[] PROGMEM = "http://arksecurity.net16.net";

byte Ethernet::buffer[700];
static uint32_t timer = 0;

static void response_callback (byte status, word off, word len){
Serial.print((const char*) Ethernet::buffer + off + HTTP_HEADER_OFFSET);
}

void setup() {
Serial.begin(57600);
if (ether.begin(sizeof Ethernet::buffer, mymac, 8) == 0)
Serial.println("Failed to access Ethernet controller");
else
Serial.println("Ethernet controller initialized");
ether.staticSetup(myip, gatewayip, dnsip);

if(!ether.dnsLookup(website)){
Serial.println("DNS failed");
while(1);
}
else
Serial.println("DNS resolution done");

ether.printIp("SRV IP:\t", ether.hisip);
Serial.println();
}
void loop() {
word pos = ether.packetLoop(ether.packetReceive());

if (millis() > timer){
timer = millis() + 5000;
ether.browseUrl("/", "test.php", website, response_callback);
}
}

Я что-то здесь не так делаю?

Edit2: Хорошо, я запустил его. Проблема с DNS была вызвана моим маршрутизатором, поэтому мне пришлось установить его на 192.168.1.1, и мне также пришлось внести некоторые изменения в ether.browseUrl, потому что он также возвращал ошибку.
Вот как теперь выглядит мой код:

#include <enc28j60.h>
#include <EtherCard.h>
#include <net.h>

#define HTTP_HEADER_OFFSET 50

/* Setup for Ethernet Library */
static byte mymac[] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x31 };
static byte myip[] = {192,168,1,58};
static byte gatewayip[] = {192,168,1,1};
static byte dnsip[] = {192,168,1,1}; //Google DNS
const char website[] PROGMEM = "www.arksecurity.net16.net";

byte Ethernet::buffer[700];
static uint32_t timer = 0;

static void response_callback (byte status, word off, word len){
Serial.print((const char*) Ethernet::buffer + off + HTTP_HEADER_OFFSET);
}

void setup() {
Serial.begin(57600);
if (ether.begin(sizeof Ethernet::buffer, mymac, 8) == 0)
Serial.println("Failed to access Ethernet controller");
else
Serial.println("Ethernet controller initialized");
ether.staticSetup(myip, gatewayip, dnsip);

if(!ether.dnsLookup(website)){
Serial.println("DNS failed");
while(1);
}
else
Serial.println("DNS resolution done");

ether.printIp("SRV IP:\t", ether.hisip);
Serial.println();
}
void loop() {
word pos = ether.packetLoop(ether.packetReceive());

if (millis() > timer){
timer = millis() + 5000;
ether.browseUrl(PSTR("/test."),"php", website, response_callback);
}
}

Теперь мне нужно сохранить данные, которые я получаю в char * []. Есть идеи?

Edit3:

Вот так выглядит мой код. Дело в том, что при последнем сравнении, которое я делаю «для (int i = 0; i < 20 — 1; я ++) «Я получаю все» Неправильно «, как и первые два ответных отклика, и после этого он начинает получать одно» ОК «, как и должно. Ожидается ли это?

После этого я хотел бы, чтобы он вызывал response_callback только один раз в день, как в полночь. Является ли это возможным?

#define HTTP_HEADER_OFFSET 163
#define MAX_STRINGS 20
#define MAX_STRING_LENGTH 8
#define REQUEST_EVERY_X_MS 5000

/* Setup for Ethernet Library */
static byte mymac[] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x31 };
const char website[] PROGMEM = "www.arksecurity.net16.net";
const char device[] = "0001";
char test[MAX_STRINGS][MAX_STRING_LENGTH+1];
String test2 = "1234";
char * comp[20];
uint8_t receivedResponse;
unsigned long timer;

byte Ethernet::buffer[700];

static void response_callback (byte status, word off, word len) {

int i_string = 0;
int i_char = 0;
int i_ethBuff = off + HTTP_HEADER_OFFSET;
char carat;
for (i_ethBuff = off + HTTP_HEADER_OFFSET; (carat =(char)Ethernet::buffer[i_ethBuff]) != 0; i_ethBuff++)
{
if (carat == '\n')
{ // New line char = new string
if (i_string < MAX_STRINGS - 1){
i_string++;
i_char = 0;
}
else
break;
}
else
{
if (i_char < MAX_STRING_LENGTH)
{
test[i_string][i_char] = carat;
i_char++;
} // otherwise discard the char (max length of string reached)
}
}
receivedResponse = 1;
}
void setup() {
if (ether.begin(sizeof Ethernet::buffer, mymac, 8) == 0)
{
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");

if (!ether.dnsLookup(website))
{
Serial.println("DNS failed");
while(1);
}
else
Serial.println("DNS resolution done");

ether.printIp("SRV IP:\t", ether.hisip);
Serial.println();
timer = millis() - REQUEST_EVERY_X_MS;
}

void loop() {
word pos = ether.packetLoop(ether.packetReceive());

if (millis() - timer > REQUEST_EVERY_X_MS){
timer += REQUEST_EVERY_X_MS;
receivedResponse = 0;
ether.browseUrl(PSTR("/DevicesQuery.php?device="),device , website, response_callback);

while (!receivedResponse);
for(int i=0; i < 20 - 1; i++){
comp[i] = test[i];
if(test2.equals(comp[i])){
Serial.println("OK");
}
else
Serial.println("Wrong");
}

}

}

Edit4: сделал это работать с другим сравнением. Я хочу, чтобы он получал данные каждые 5 секунд, пока он не получит что-нибудь, и они заставят его долго ждать. Проблема в том, что когда я делаю timer2 = 500000; это фактически делает это ловить данные еще быстрее. Это почему?

#include <enc28j60.h>
#include <EtherCard.h>
#include <net.h>

#define HTTP_HEADER_OFFSET 163
#define MAX_STRINGS 10
#define MAX_STRING_LENGTH 20
#define REQUEST_EVERY_X_MS 5000/* Setup for Ethernet Library */
static byte mymac[] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x31 };
const char website[] PROGMEM = "www.arksecurity.net16.net"; //link para o banco de dados do usuário em questão
const char device[] = "0001"; // adicionar aqui o número do dispositivo equivalente ao que aparece no Bando de Dados
char test[MAX_STRINGS][MAX_STRING_LENGTH+1];
String test2 = "9999";
//uint8_t receivedResponse;
unsigned long timer;
unsigned long timer2 = 5000;

byte Ethernet::buffer[700];

static void response_callback (byte status, word off, word len) {
for(int i=0;i<MAX_STRINGS;i++)
for(int j=0;j<=MAX_STRING_LENGTH;j++)
test[i][j] = 0;

int i_string = 0;
int i_char = 0;
int i_ethBuff = off + HTTP_HEADER_OFFSET;
char carat;
for (i_ethBuff = off + HTTP_HEADER_OFFSET; (carat = (char)Ethernet::buffer[i_ethBuff]) != 0; i_ethBuff++)
{
if (carat == '\n')
{ // New line char = new string
if (i_string < MAX_STRINGS - 1){
i_string++;
i_char = 0;
}
else
break; // Limite de memória do Arduino
}
else
{
if (i_char < MAX_STRING_LENGTH)
{
test[i_string][i_char] = carat;
i_char++;
} // otherwise discard the char (max length of string reached)
}
}
//receivedResponse[0] = 1;
}void setup() {
Serial.begin(57600);
if (ether.begin(sizeof Ethernet::buffer, mymac, 53) == 0)
{
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");

if (!ether.dnsLookup(website))
{
Serial.println("DNS failed");
while(1);
}
else
Serial.println("DNS resolution done");

ether.printIp("SRV IP:\t", ether.hisip);
Serial.println();

timer = millis() - timer2;
}

void loop() {

word pos = ether.packetLoop(ether.packetReceive());

if (millis() - timer > timer2)
{
ether.browseUrl(PSTR("/DevicesQuery.php?device="),device , website, response_callback);

if(test[0][0] != 0){
Serial.println("Data Received");
Serial.println(test[0]);
Serial.println(test[1]);
Serial.println(test[2]);
Serial.println(test[3]);
Serial.println(test[4]);
Serial.println(test[5]);
timer2 = 500000;
}
else{
Serial.println("Nothing");
timer2 = 5000;
}
timer += timer2;
}

Edit5: я добавил эту часть в свой код, чтобы я также мог отправлять данные на свой сервер, но у меня почему-то отправляются только одни данные, даже если я использую цикл для этого. Почему это происходит?

Код:

for(int i = 0; i < countRegister ; i++)
{
register[i].toCharArray(tempRegister, 80);
ether.browserUrl(PTSR("/log.php"), tempRegister , browser_callback);
}static void browser_callback (byte status, word off, word len)
{
Serial.println("Data sent");
}

0

Решение

Прежде всего, все это не проверено на всех. Я все еще жду прибытия своей доски, так что … Я использую большой набор учебных пособий, которые я нашел в Интернете (однако они на итальянском языке). в частности Вот учебник о том, как получить данные с сервера.

Хорошо, сначала вы должны настроить плату ENC28J60 со всеми необходимыми параметрами, такими как MAC-адрес и конфигурация IP. В примере я использовал DHCP, но вы можете использовать статическую конфигурацию (надеюсь, вы знаете, как это сделать).

Затем вы должны проверить, можете ли вы разрешить имя веб-сайта (DNS-запрос) — не уверены, действительно ли это необходимо).

Затем просто опросите веб-сайт (в этом примере каждые 5 секунд) и проанализируйте пакет.

Вот код:

#include <EtherCard.h>

#define HTTP_HEADER_OFFSET 0
static byte mymac[] = {0x12,0x34,0x56,0x78,0x90,0xAB};
char website[] PROGMEM = "www.yourwebsite.com";

byte Ethernet::buffer[700];
static uint32_t timer = 0;

static void response_callback (byte status, word off, word len) {
Serial.print((const char*) Ethernet::buffer + off + HTTP_HEADER_OFFSET);
}

void setup () {
Serial.begin(57600);

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");

if (!ether.dnsLookup(website))
{
Serial.println("DNS failed");
while(1);
}
else
Serial.println("DNS resolution done");

ether.printIp("SRV IP:\t", ether.hisip);
Serial.println();
}

void loop() {
ether.packetLoop(ether.packetReceive());

if (millis() > timer) {
timer = millis() + 5000;
ether.browseUrl("/", "yourpage.php", website, response_callback);
}
}

Вывод этого эскиза на последовательной консоли будет примерно таким (картинка взята из учебника, о котором я упоминал ранее)

Заголовок http

Как видите, перед самой страницей есть заголовок. Вам просто нужно посчитать, сколько у них символов, и поместить это значение в HTTP_HEADER_OFFSET.

Другой способ, если этот заголовок меняется, — это добавить что-то перед текущим сообщением (например, обернуть все в <body> тег) и искать его.

В любом случае, в response_callback Функция у вас будут все ваши данные в Ethernet::buffer + off + header_offset, Затем вы должны разобрать его и поместить в массив, но я надеюсь, что вы можете сделать это самостоятельно …

РЕДАКТИРОВАТЬ:

Чтобы использовать статический IP-адрес, вы должны установить его следующим образом:

static byte myip[] = {192,168,1,10};
static byte gatewayip[] = {192,168,1,1};
//static byte dnsip[] = {8,8,8,8}; // Google DNS; change if you want to use another
static byte dnsip[] = {192,168,1,1}; // The OP said that with google dns something was not working
...
ether.staticSetup(myip, gatewayip, dnsip);

EDIT2:

Ну, поскольку у вас уже есть данные в виде строки, их действительно легко разбить на куски. Одно из возможных решений:

#define MAX_STRINGS 10
#define MAX_STRING_LENGTH 10

char test[MAX_STRINGS][MAX_STRING_LENGTH+1];

static void response_callback (byte status, word off, word len) {
for(int i=0;i<MAX_STRINGS;i++)
for(int j=0;j<=MAX_STRING_LENGTH;j++)
test[i][j] = 0;

int i_string = 0;
int i_char = 0;
int i_ethBuff = off + HTTP_HEADER_OFFSET;
char carat;
for (i_ethBuff = off + HTTP_HEADER_OFFSET; (carat = (char)Ethernet::buffer[i_ethBuff]) != 0; i_ethBuff++)
{
if (carat == '\n')
{ // New line char = new string
if (i_string < MAX_STRINGS-1)
i_string++;
else
break; // Too many strings; discarding all the other ones
}
else
{
if (i_char < MAX_STRING_LENGTH)
{
test[i_string][i_char] = carat;
i_char++;
} // otherwise discard the char (max length of string reached
}
}
}

Если одна из длин меньше 255, вы можете изменить счетчик int на uint8_t.

EDIT3:

Чтобы обнаружить строки как разделители, это немного сложнее. Например, чтобы обнаружить "<br>", вы можете:

char separator[] = "<br>";

for (i_ethBuff = off + HTTP_HEADER_OFFSET; (carat = (char)Ethernet::buffer[i_ethBuff]) != 0; i_ethBuff++)
{
if (i_char < MAX_STRING_LENGTH)
{
test[i_string][i_char] = carat;
i_char++;

uint8_t stringDetected = 0;
if (i_char >= sizeof(separator))
{
int i_sep;
stringDetected = 1;
for (i_sep = 0; i_sep < sizeof(separator) && (stringDetected); i_sep++)
{ // You can try to detect it
if (test[i_string][i_char - sizeof(separator) + i_sep] != separator[i_sep]);
stringDetected = 0;
}
}

if (stringDetected)
{
test[i_string][i_char - sizeof(separator)] = '\0';
if (i_string < MAX_STRINGS-1)
i_string++;
else
break; // Too many strings; discarding all the other ones
}
}
}

Я надеюсь, что это сработает (возможно, вам нужно исправить счетчики на +/- 1 (не знаю, будет ли sizeof возвращать завершающий \ 0).

Просто не забудьте увеличить пространство для отдельных строк (они также должны будут хранить разделитель)

РЕДАКТИРОВАТЬ 4:

Что касается неправильного теста, я думаю, что это потому, что вы еще не получили ответ. Вы можете дождаться ответа, прежде чем тестировать.

Более того, я заметил небольшую ошибку в таймере: вы должны сделать его беззнаковым длинным и проверить миллис () — таймер, а не миллис ()> таймер, иначе у вас будут проблемы при опрокидывании таймера. Я исправил это в этом коде:

// Before the setup
#define REQUEST_EVERY_X_MS 5000
uint8_t receivedResponse;
unsigned long timer;

// At the end of setup
timer = millis() - REQUEST_EVERY_X_MS;

// Inside response callback
for (i_ethBuff = off + HTTP_HEADER_OFFSET; (carat = (char)Ethernet::buffer[i_ethBuff]) != 0; i_ethBuff++)
{
...
}
receivedResponse = 1;

// In the main loop
if (millis() - timer > REQUEST_EVERY_X_MS)
{
timer += REQUEST_EVERY_X_MS;
receivedResponse = 0;
ether.browseUrl(PSTR("/DevicesQuery.php?device="),device , website, response_callback);

while (!receivedResponse);
for(int i=0; i < 20 - 1; i++)
{
comp[i] = test[i];
if(test2.equals(comp[i]))
Serial.println("OK");
else
Serial.println("Wrong");
}
}

Что касается выполнения его один раз в день, если вы хотите выполнить его точно в полночь, вам понадобится какой-то способ отслеживать время (например, RTC или использование протокола NTP с Ethernet). Это не совсем тривиально, но вы можете найти множество примеров того, как использовать RTC.

Если, с другой стороны, вы хотите выполнить его только один раз в день (независимо от времени), просто измените определение REQUEST_EVERY_X_MS к правильному значению (24 ч = 1440 мин = 86400 с = 86400000 мс, поэтому #define REQUEST_EVERY_X_MS 86400000) и он должен запускаться в тот момент, когда вы его включаете, а затем каждые 24 часа. Вы можете использовать периоды до 4294967294 мс или примерно 49 дней.

РЕДАКТИРОВАТЬ 5:

Хорошо, глядя на мысли других людей (в основном по ссылке, предоставленной ФП в комментариях ниже), похоже, что

  1. browseUrl не любит, когда его вызывают дважды перед завершением предыдущего раза
  2. обратные вызовы живут не в прерываниях, а в основном коде. Следовательно, вы не можете заблокировать программу.

Итак … Попробуйте реализовать это для последующих вызовов:

volatile uint8_t receivedResponse;

// in the main
for(int i = 0; i < countRegister ; i++)
{
register[i].toCharArray(tempRegister, 80);
receivedResponse = 0;
ether.browserUrl(PTSR("/log.php"), tempRegister , browser_callback);
while (!receivedResponse)
ether.packetLoop(ether.packetReceive());
}

// the callback
static void browser_callback (byte status, word off, word len)
{
Serial.println("Data sent");
receivedResponse = 1;
}

Надеюсь, что это решает все проблемы;)

0

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector