По умолчанию на HiWath, Hikvision и подобных камерах установлена безопасность авторизации: digest.
А в Arduino нет нативной (из коробки) поддержки digest auth. Поэтому пишем реализацию прохождения digest auth:
(за основу взято: github)
/*
This sketch shows how to handle HTTP Digest Authorization.Written by Parham Alvani and Sajjad Rahnama, 2018-01-07.
This example is released into public domain,
or, at your option, CC0 licensed.
*/#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#ifndef STASSID
#define STASSID "YOUR_SSID"
#define STAPSK "YOUR_PASSWORD"
#endifconst char* ssid = STASSID;
const char* ssidPassword = STAPSK;const char* username = "admin";
const char* password = "password";// XML данные, которые будут отправлены в PUT-запросе
const char* xmlPayload = R"(
<VideoOverlay xmlns="http://www.std-cgi.com/ver20/XMLSchema" version="2.0">
<TextOverlayList size="4">
<TextOverlay>
<id>1</id>
<enabled>true</enabled>
<positionX>672</positionX>
<positionY>128</positionY>
<displayText>test_OSD_text</displayText>
</TextOverlay>
</TextOverlayList>
</VideoOverlay>
)";const char* server = "http://192.168.1.36";
const char* uri = "/ISAPI/System/Video/inputs/channels/1/overlays";String exractParam(String& authReq, const String& param, const char delimit) {
int _begin = authReq.indexOf(param);
if (_begin == -1) { return ""; }
return authReq.substring(_begin + param.length(), authReq.indexOf(delimit, _begin + param.length()));
}String getCNonce(const int len) {
static const char alphanum[] = "0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
String s = "";for (int i = 0; i < len; ++i) { s += alphanum[rand() % (sizeof(alphanum) - 1)]; }
return s;
}String getDigestAuth(String& authReq, const String& username, const String& password, const String& method, const String& uri, unsigned int counter) {
// extracting required parameters for RFC 2069 simpler Digest
String realm = exractParam(authReq, "realm=\"", '"');
String nonce = exractParam(authReq, "nonce=\"", '"');
String cNonce = getCNonce(8);char nc[9];
snprintf(nc, sizeof(nc), "%08x", counter);// parameters for the RFC 2617 newer Digest
MD5Builder md5;
md5.begin();
md5.add(username + ":" + realm + ":" + password); // md5 of the user:realm:user
md5.calculate();
String h1 = md5.toString();md5.begin();
md5.add(method + ":" + uri);
md5.calculate();
String h2 = md5.toString();md5.begin();
md5.add(h1 + ":" + nonce + ":" + String(nc) + ":" + cNonce + ":" + "auth" + ":" + h2);
md5.calculate();
String response = md5.toString();String authorization = "Digest username=\"" + username + "\", realm=\"" + realm + "\", nonce=\"" + nonce + "\", uri=\"" + uri + "\", algorithm=\"MD5\", qop=auth, nc=" + String(nc) + ", cnonce=\"" + cNonce + "\", response=\"" + response + "\"";
Serial.println(authorization);return authorization;
}void setup() {
randomSeed(RANDOM_REG32);
Serial.begin(115200);WiFi.mode(WIFI_STA);
WiFi.begin(ssid, ssidPassword);while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}void loop() {
WiFiClient client;
HTTPClient http; // must be declared after WiFiClient for correct destruction order, because used by http.begin(client,...)Serial.print("[HTTP] begin...\n");
// configure traged server and url
http.begin(client, String(server) + String(uri));
const char* keys[] = { "WWW-Authenticate" };
http.collectHeaders(keys, 1);Serial.print("[HTTP] GET...\n");
// start connection and send HTTP header
int httpCode = http.GET();if (httpCode > 0) {
String authReq = http.header("WWW-Authenticate");
Serial.println(authReq);String authorization = getDigestAuth(authReq, String(username), String(password), "GET", String(uri), 1);
http.end();
http.begin(client, String(server) + String(uri));http.addHeader("Authorization", authorization);
int httpCode = http.GET();
if (httpCode > 0) {
String payload = http.getString();
Serial.println(payload);
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}http.end();
delay(10000);
}
Связанные заметки:
P.S.: Если что-то пошло не так — пишите в Telegram (ник: first_Andres) - разберёмся.