Модуль Пинг

This commit is contained in:
Mit4el
2024-03-01 22:00:38 +03:00
parent 8aecb4b001
commit ab0d5f40e2
3 changed files with 361 additions and 0 deletions

View File

@@ -0,0 +1,240 @@
#include "Global.h"
#include "classes/IoTItem.h"
#include <ArduinoJson.h>
#ifdef ESP32
#include "sdkconfig.h"
#include "lwip/inet.h"
#include "lwip/netdb.h"
#include "lwip/sockets.h"
#include "argtable3/argtable3.h"
#include "ping/ping_sock.h"
#endif
#ifdef ESP8266
#include <ESP8266Ping.h>
#endif
#ifdef ESP32
bool pingState = false;
/*
static struct
{
uint32_t timeout;
uint32_t interval;
uint32_t data_size;
uint32_t count;
uint32_t tos;
uint32_t ttl;
//String host;
// arg_end *end;
} ping_args;
*/
esp_ping_config_t config = ESP_PING_DEFAULT_CONFIG();
static void cmd_ping_on_ping_success(esp_ping_handle_t hdl, void *args)
{
uint8_t ttl;
uint16_t seqno;
uint32_t elapsed_time, recv_len;
ip_addr_t target_addr;
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
esp_ping_get_profile(hdl, ESP_PING_PROF_TTL, &ttl, sizeof(ttl));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len));
esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time));
// Serial.printf("%" PRIu32 " bytes from %s icmp_seq=%" PRIu16 " ttl=%" PRIu16 " time=%" PRIu32 " ms\n",
// recv_len, ipaddr_ntoa((ip_addr_t*)&target_addr), seqno, ttl, elapsed_time);
SerialPrint("i", "Ping", String(recv_len) + " bytes from " + String(ipaddr_ntoa((ip_addr_t *)&target_addr)) + " icmp_seq=" + String(seqno) + " ttl=" + String(ttl) + " time=" + String(elapsed_time) + " ms");
pingState = true;
}
static void cmd_ping_on_ping_timeout(esp_ping_handle_t hdl, void *args)
{
uint16_t seqno;
ip_addr_t target_addr;
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
// Serial.printf("From %s icmp_seq=%d timeout\n",ipaddr_ntoa((ip_addr_t*)&target_addr), seqno);
SerialPrint("i", "Ping", "From " + String(ipaddr_ntoa((ip_addr_t *)&target_addr)) + " icmp_seq=" + String(seqno) + " timeout");
pingState = false;
}
static void cmd_ping_on_ping_end(esp_ping_handle_t hdl, void *args)
{
ip_addr_t target_addr;
uint32_t transmitted;
uint32_t received;
uint32_t total_time_ms;
esp_ping_get_profile(hdl, ESP_PING_PROF_REQUEST, &transmitted, sizeof(transmitted));
esp_ping_get_profile(hdl, ESP_PING_PROF_REPLY, &received, sizeof(received));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
esp_ping_get_profile(hdl, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms));
uint32_t loss = (uint32_t)((1 - ((float)received) / transmitted) * 100);
if (IP_IS_V4(&target_addr))
{
// Serial.printf("\n--- %s ping statistics ---\n", inet_ntoa(*ip_2_ip4(&target_addr)));
SerialPrint("i", "Ping", "\n--- " + String(inet_ntoa(*ip_2_ip4(&target_addr))) + " ping statistics ---");
}
else
{
// Serial.printf("\n--- %s ping statistics ---\n", inet6_ntoa(*ip_2_ip6(&target_addr)));
SerialPrint("i", "Ping", "\n--- " + String(inet6_ntoa(*ip_2_ip6(&target_addr))) + " ping statistics ---");
}
// Serial.printf("%" PRIu32 " packets transmitted, %" PRIu32 " received, %" PRIu32 "%% packet loss, time %" PRIu32 "ms\n",
// transmitted, received, loss, total_time_ms);
SerialPrint("i", "Ping", String(transmitted) + " packets transmitted, " + String(received) + " received, " + String(loss) + "% packet loss, time " + String(total_time_ms) + "ms\n");
// delete the ping sessions, so that we clean up all resources and can create a new ping session
// we don't have to call delete function in the callback, instead we can call delete function from other tasks
esp_ping_delete_session(hdl);
}
#endif
class PingIoTM : public IoTItem
{
private:
String _ip = "";
int timeout = 0;
int interval = 0;
int data_size = 0;
int count = 0;
int tos = 0;
int ttl = 0;
public:
PingIoTM(String parameters) : IoTItem(parameters)
{
jsonRead(parameters, "ip", _ip);
jsonRead(parameters, "timeout", timeout);
jsonRead(parameters, "interval", interval);
jsonRead(parameters, "data_size", data_size);
jsonRead(parameters, "count", count);
jsonRead(parameters, "tos", tos);
jsonRead(parameters, "ttl", ttl);
#ifdef ESP32
/*
ping_args.timeout = 10; // arg_dbl0("W", "timeout", "<t>", "Time to wait for a response, in seconds");
ping_args.interval = 1; // arg_dbl0("i", "interval", "<t>", "Wait interval seconds between sending each packet");
ping_args.data_size = 0; // arg_int0("s", "size", "<n>", "Specify the number of data bytes to be sent");
ping_args.count = 0; // arg_int0("c", "count", "<n>", "Stop after sending count packets");
ping_args.tos = 0; // arg_int0("Q", "tos", "<n>", "Set Type of Service related bits in IP datagrams");
ping_args.ttl = 0; // arg_int0("T", "ttl", "<n>", "Set Time to Live related bits in IP datagrams");
// ping_args.end = arg_end(1);
*/
if (timeout > 0)
config.timeout_ms = (uint32_t)(timeout * 1000);
if (interval > 0)
config.interval_ms = (uint32_t)(interval * 1000);
if (data_size > 0)
config.data_size = (uint32_t)(data_size);
if (count > 0)
config.count = (uint32_t)(count);
if (tos > 0)
config.tos = (uint32_t)(tos);
if (ttl > 0)
config.ttl = (uint32_t)(ttl);
#endif
}
void doByInterval()
{
#ifdef ESP8266
regEvent((float)Ping.ping(_ip.c_str()), "ping");
#endif
}
// Основной цикл программы
void loop()
{
#ifdef ESP32
if (value.valD != (float)pingState)
regEvent((float)pingState, "ping");
#endif
IoTItem::loop();
}
IoTValue execute(String command, std::vector<IoTValue> &param)
{
IoTValue val;
if (command == "ping")
{
#ifdef ESP32
if (param.size())
{
// parse IP address
struct sockaddr_in6 sock_addr6;
ip_addr_t target_addr;
memset(&target_addr, 0, sizeof(target_addr));
if (inet_pton(AF_INET6, _ip.c_str(), &sock_addr6.sin6_addr) == 1)
{
/* convert ip6 string to ip6 address */
ipaddr_aton(_ip.c_str(), &target_addr);
}
else
{
struct addrinfo hint;
struct addrinfo *res = NULL;
memset(&hint, 0, sizeof(hint));
/* convert ip4 string or hostname to ip4 or ip6 address */
if (getaddrinfo(_ip.c_str(), NULL, &hint, &res) != 0)
{
// Serial.printf("ping: unknown host %s\n", ping_args.host.c_str());
SerialPrint("E", "Ping", "ping: unknown host " + _ip);
// return 1;
}
if (res->ai_family == AF_INET)
{
struct in_addr addr4 = ((struct sockaddr_in *)(res->ai_addr))->sin_addr;
inet_addr_to_ip4addr(ip_2_ip4(&target_addr), &addr4);
}
else
{
struct in6_addr addr6 = ((struct sockaddr_in6 *)(res->ai_addr))->sin6_addr;
inet6_addr_to_ip6addr(ip_2_ip6(&target_addr), &addr6);
}
freeaddrinfo(res);
}
config.target_addr = target_addr;
/* set callback functions */
esp_ping_callbacks_t cbs = {
.cb_args = NULL,
.on_ping_success = cmd_ping_on_ping_success,
.on_ping_timeout = cmd_ping_on_ping_timeout,
.on_ping_end = cmd_ping_on_ping_end};
esp_ping_handle_t ping;
esp_ping_new_session(&config, &cbs, &ping);
esp_ping_start(ping);
}
#endif
#ifdef ESP8266
if (param.size())
{
val.valD = Ping.ping(param[0].valS.c_str());
if (val.valD)
SerialPrint("I", "Ping", "Ping success");
else
SerialPrint("E", "Ping", "Ping error");
regEvent(val, "ping");
return val;
}
#endif
}
return {};
}
~PingIoTM(){};
};
void *getAPI_Ping(String subtype, String param)
{
if (subtype == F("Ping"))
{
return new PingIoTM(param);
}
else
{
return nullptr;
}
}

View File

@@ -0,0 +1,68 @@
{
"menuSection": "virtual_elments",
"configItem": [
{
"global": 0,
"name": "Ping",
"type": "Reading",
"subtype": "Ping",
"id": "ping",
"needSave": 0,
"widget": "nil",
"page": "",
"descr": "",
"ip": "8.8.8.8",
"timeout": 5,
"interval": 1,
"data_size": 0,
"count": 0,
"tos": 0,
"ttl": 0
}
],
"about": {
"authorName": "Mikhail Bubnov",
"authorContact": "https://t.me/Mit4bmw",
"authorGit": "https://github.com/Mit4el",
"specialThanks": "",
"moduleName": "Ping",
"moduleVersion": "1.0",
"usedRam": {
"esp32_4mb": 15,
"esp8266_4mb": 15
},
"title": "Пинг",
"moduleDesc": "Пинг - проверка доступности сетевого адреса",
"propInfo": {
"ip": "IP адрес (8.8.8.8) или имя хоста (www.google.com) кого пингуем",
"timeout": "Тайм-аут. Только для ESP32. Если 0, то пингует со значением по умолчанию",
"interval": "Интервал. Только для ESP32. Если 0, то пингует со значением по умолчанию",
"data_size": "Размер пакета. Только для ESP32. Если 0, то пингует со значением по умолчанию",
"count": "Количество пакетов. Только для ESP32. Если 0, то пингует со значением по умолчанию",
"tos": "Type Of Service. Только для ESP32. Если 0, то пингует со значением по умолчанию",
"ttl": "Time To Live. Только для ESP32. Если 0, то пингует со значением по умолчанию"
},
"funcInfo": [
{
"name": "ping",
"descr": "проверить пинг вручную из сценария",
"params": [
"IP адрес или имя хоста"
]
}
]
},
"defActive": true,
"usedLibs": {
"esp32*": [
],
"esp82*": [
"https://github.com/dancol90/ESP8266Ping"
]
}
}

View File

@@ -0,0 +1,53 @@
{
"mark": "iotm",
"config": [
{
"global": 0,
"type": "Reading",
"subtype": "VButton",
"id": "vbtn67",
"needSave": 0,
"widget": "toggle",
"page": "Пинг",
"descr": "ping",
"int": "0",
"val": "0"
},
{
"global": 0,
"type": "Reading",
"subtype": "Variable",
"id": "vout96",
"needSave": 0,
"widget": "anydataDef",
"page": "Пинг",
"descr": "Состояние",
"int": "0",
"val": "...",
"map": "1024,1024,1,100",
"plus": 0,
"multiply": 1,
"round": 0
},
{
"global": 0,
"type": "Reading",
"subtype": "Ping",
"id": "ping21",
"needSave": 0,
"widget": "anydataDef",
"page": "Пинг",
"descr": "Статус",
"ip": "8.8.8.8",
"timeout": 5,
"interval": 1,
"data_size": 0,
"count": 0,
"tos": 0,
"ttl": 0
}
]
}
scenario=>if vbtn67==1 then ping21.ping("8.8.8.8")
if ping21==0 then vout96 = "нет интернета" else vout96 ="есть интернет"