Я пытаюсь внедрить базовую систему «датчик-облако», отправляющую данные из микроконтроллера ESP8266 в облако IoT Azure по протоколам RESTful HTTP / HTTPS.
Используется интерпретатор NodeMCU Lua.
Для краткости я опустил здесь код, который фактически считывает датчики и подключается к WiFi-сети. Они работают правильно.
Я успешно работал с HTTP POST для UbiDots, но я не могу заставить Azure работать - я думаю, что принудительный HTTPS - это та часть, с которой я не могу работать.
Я сгенерировал токен SAS, настроил IoT-концентратор Azure, и я почти уверен, что HTTP-заголовок правильный, а строка авторизации включена в SAS, который я сгенерировал из средства обозревателя IOT-концентраторов Azure.
=== РЕДАКТИРОВАТЬ ===
My NodeMCU build is as follows:
NodeMCU custom build by frightanic.com
branch: dev
commit: 5e1ca234cce36f251edd78dc3d5a5ce4d4c76a59
SSL: true
modules: adc,crypto,ds18b20,file,gpio,http,hx711,net,node,ow,sntp,tmr,uart,wifi,tls
build created on 2018-04-26 07:02
powered by Lua 5.1.4 on SDK 2.2.1(cfd48f3)
Теперь я сделал все намного лучше с помощью рефакторинга, использующего библиотеку NodeMCU HTTP (S). Соответствующий код следующим образом:
function postHTTPWebService(name1, val1, name2, val2, name3, val3, name4, val4)
tls.cert.verify([[
-----BEGIN CERTIFICATE-----
-- certificate mostly redacted
MIIFtDCCBJygAwIBAgIQCLh6UBu+nNotFk0+OVG/VTANBgkqhkiG9w0BAQsFADBa
86Qho5jQenT2jOjD0iuqK84RWRlE51wHCULr1/0VTblvbEQ1Joe6oztosIHnIMl/
EwLzzKufHJVQy65kgLuHCl3OpmuyfeM9NuIpUbcl/NAJ47CtxGIuPn6FJrL2r/dt
N2UI+5Gz6BZ2YSpl9ViUs0UB78BPA3u4
-----END CERTIFICATE-----
]])
tls.cert.verify(true)
azure_url =
"https://" .. AZURE_HUB .. ".azure-devices.net/devices/" ..
AZURE_DEVICE .. "/messages/events?api-version=" .. AZURE_API
azure_payload = json(name1, val1, name2, val2, name3, val3, name4, val4)
azure_headers =
"Authorization: " .. SAS_TOKEN .. "\r\n" ..
"Content-Type: application/json\r\n" ..
"Content-Length: " .. string.len(azure_payload) .. "\r\n" ..
"Host: " .. AZURE_HUB .. ".azure-devices.net\r\n\n"
http.post(azure_url, azure_headers, azure_payload,
function(return_status, return_payload)
if (return_status < 0) then -- big fail, no HTTP return at all
print("HTTP request failed")
elseif (return_status == 200) then
print(return_payload)
print("Got HTTP 200 return - entering deep sleep")
node.dsleep(DEEPSLEEP_TIME)
else
-- There are many HTTP codes which are valid but still unsuccessful
print("Got valid return status - not 200")
print(return_status, return_payload)
end
end)
end
Когда я использую tls.cert.verify(true)
, я получаю следующий вывод:
E:M 1472
E:M 1520
E:M 1520
HTTP client: Disconnected with error: 88
HTTP client: Connection timeout
HTTP request failed
Теперь давайте попробуем tls.cert.verify(false)
E:M 40
E:M 1520
E:M 1520
E:M 120
HTTP client: Disconnected with error: -123
HTTP client: Connection timeout
HTTP request failed
И попробуйте tls.cert.verify(false)
еще раз:
E:M 264
E:M 1520
E:M 1520
HTTP client: Disconnected with error: -16
HTTP client: Connection timeout
HTTP request failed
=== КОНЕЦ РЕДАКТИРОВАНИЯ ===
Я понял, что библиотека HTTP сделает код немного аккуратнее, но на данный момент я уже написал код без его использования, и я еще не вернулся и не отредактировал его, чтобы использовать HTTP-библиотеку и т. Д. Я думаю, что он все еще должен работать с использованием общей библиотеки сокетов, а действительно все еще работает для незащищенного простого HTTP-сообщения, поэтому я бы хотел, чтобы что-то работало прямо сейчас с минимальными изменениями.
Следующая неисправная часть, я думаю
serv_addr = AZURE_HUB .. ".azure-devices.net"
tls.cert.verify(true)
connection:connect(443, serv_addr)
end
Это правильная структура адреса сервера, правильный порт и правильное использование tls, а также правильный cert.verify ()?
Минимальный рабочий пример успешного взаимодействия с Azure может быть очень хорошим, если кто-нибудь знает, где его найти для NodeMCU. Я еще не нашел.
В настоящий момент для меня это немного головная боль, но я полагаю, хорошо, что они в значительной степени форсируют переход к относительно безопасным сквозным системам для устройств пограничных узлов IoT.
Я ранее сгенерировал сертификат:
tls.cert.verify([[
-----BEGIN CERTIFICATE-----
foo blah blah blah here is the certificate generated
-----END CERTIFICATE-----
]])
tls.cert.verify(true)
Так что теперь, когда мой код вызывает tls.cert.verify (true), этот сертификат уже должен храниться во флэш-памяти.
AZURE_DEVICE = "MyAzureDeviceName"
AZURE_HUB = "myazureiothub"
AZURE_API = "2016-02-03"
SAS_TOKEN = "123AFthisisafaketokenC4%3D"
DEEPSLEEP_TIME = 60000000 -- 1 minute in microseconds
local module = {}
function format_json(variable1, value1, variable2, value2, variable3, value3, variable4, value4)
payload =
'{\"' .. variable1..'\": {"value": ' .. value1..'},\"'
.. variable2 .. '\": {"value": ' .. value2 .. '},\"'
.. variable3 .. '\": {"value": ' .. value3 .. '},\"'
.. variable4 .. '\": {"value": ' .. value4 .. '}}'
return payload
end
function postHTTPWebService(name1, value1, name2, value2, name3, value3, name4, value4)
connection = tls.createConnection(net.TCP, 0)
connection:on("receive", function(connection, payload)
if (string.find(payload, "200 OK") ~= nil) then
print("HTTP 200 received - OK");
connection:close();
collectgarbage();
node.dsleep(DEEPSLEEP_TIME)
else
print("HTTP Return Error")
print(payload) -- print the HTTP status returned.
end
end)
connection:on("connection", function(connection, payload)
data = format_json(name1, value1, name2, value2, name3, value3, name4, value4)
local post = "POST /devices/" .. AZURE_HUB .. "/messages/events?api-version=" .. AZURE_API .. " HTTP/1.1\r\n" ..
"Host: " .. AZURE_HUB .. ".azure-devices.net\r\n" ..
"Authorization: SharedAccessSignature " .. SAS_TOKEN .. "\r\n" ..
"Content-Type: application/json\r\n" ..
"Content-Length: " .. string.len(data) .. "\r\n" ..
"\r\n" .. data .. "\n"
print(post) -- print the full HTTP payload for debugging
connection:send(post)
print("HTTP POST sent.")
end)
connection:on("disconnection", function(connection, payload)
connection:close();
collectgarbage();
end)
serv_addr = AZURE_HUB .. ".azure-devices.net"
tls.cert.verify(true)
connection:connect(443, serv_addr)
end
function readSensors()
value1 = 1 -- Dummy sensor data for testing
value2 = 2
value3 = 3
value4 = 4
postHTTPWebService("sensor1", value1, "sensor2", value2, "sensor3", value3, "sensor4", value4)
end
local function main_function()
-- Wait a second, then run the sensor function
tmr.alarm(3, 1000, tmr.ALARM_SINGLE, function() readSensors() end)
end
function module.start()
main_function()
end
return module