我正在尝试实现一个基本的传感器到 Cloud 系统,通过RESTful HTTP / HTTPS POST将数据从ESP8266微控制器发送到Azure IoT Cloud .

使用NodeMCU Lua解释器 .

为了简洁起见,我省略了实际读取传感器并连接到WiFi LAN的代码 . 这些工作正常 .

我已经成功地使用HTTP POST到UbiDots,但我不能让Azure工作 - 我认为强制HTTPS是我无法工作的部分 .

我已经生成了一个SAS令牌,设置了Azure IoT Hub,我非常确定HTTP头是正确的,并且我从Azure的IOT中心浏览器工具生成的SAS中包含了授权行 .

===编辑===

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 lib等 . 我认为它应该仍然使用通用套接字库,并且仍然适用于不安全的普通HTTP帖子,因此我希望现在能够以最少的更改获得一些工作 .

以下是我认为的错误部分

serv_addr = AZURE_HUB .. ".azure-devices.net"
  tls.cert.verify(true)
  connection:connect(443, serv_addr)
end

这是正确的服务器地址结构,正确的端口和正确的使用,并正确的cert.verify()?

如果有人知道在哪里可以找到NodeMCU,那么成功与Azure通信的最小工作示例可能会非常好 . 我还没找到一个 .

这对我来说有点令人头疼,但我认为它们很可能会迫使向物联网边缘节点设备过渡到相对安全的端到端系统 .

我之前已经生成了证书:

tls.cert.verify([[
-----BEGIN CERTIFICATE-----
foo blah blah blah here is the certificate generated
-----END CERTIFICATE-----
]])

tls.cert.verify(true)

所以现在当我的代码调用tls.cert.verify(true)时,这个证书应该已经存储在flash中了 .

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