fork download
  1. -- Base.lua
  2.  
  3. -- Variáveis globais
  4. local ha_host = nil
  5. local ha_port = nil
  6. local ha_token = nil
  7. local socket_id = nil -- Variável para armazenar o ID do socket
  8. local auth_sent = false -- Flag para verificar se a autenticação já foi enviada
  9. local next_message_id = 1 -- ID para rastrear mensagens enviadas ao Home Assistant
  10.  
  11. -- Função para obter as configurações do Home Assistant do Configurator
  12. local function getHAConfig()
  13. local config = {}
  14. config.host = ELAN_GetIPString()
  15. config.port = tonumber(ELAN_GetIPPort())
  16. config.token = ELAN_GetConfigurationString("ha_token")
  17.  
  18. -- Validação das configurações
  19. if not config.host or config.host == "" then
  20. ELAN_Trace("Erro: Home Assistant Host não configurado.")
  21. return nil
  22. end
  23. if not config.port then
  24. ELAN_Trace("Erro: Home Assistant Port não configurada.")
  25. return nil
  26. end
  27. if not config.token or config.token == "" then
  28. ELAN_Trace("Erro: Home Assistant Token não configurado.")
  29. return nil
  30. end
  31.  
  32. return config
  33. end
  34.  
  35. -- Função para escapar caracteres especiais em strings JSON
  36. local function escape_json_string(str)
  37. -- Escapa aspas duplas e barras invertidas adicionando uma barra invertida antes delas
  38. return string.gsub(str, '(["\\])', '\\%1')
  39. end
  40.  
  41. -- Função para converter uma estrutura JSON em uma string
  42. local function table_to_json(hJSON)
  43. local json_string = "{"
  44. local first = true
  45. local i = 0
  46. while true do
  47. local hNode = ELAN_GetJSONSubNode(hJSON, hJSON, i)
  48. if not hNode then
  49. break
  50. end
  51. local key, value = ELAN_GetJSONValue(hJSON, hNode)
  52. local nodeType, nodeKey = ELAN_GetJSONNodeType(hJSON, hNode)
  53.  
  54. if not first then
  55. json_string = json_string .. ","
  56. else
  57. first = false
  58. end
  59.  
  60. -- Escapa a chave JSON
  61. local escapedNodeKey = escape_json_string(nodeKey)
  62. json_string = json_string .. "\"" .. escapedNodeKey .. "\":"
  63.  
  64. if nodeType == "String" then
  65. -- Escapa o valor JSON
  66. local escapedValue = escape_json_string(value)
  67. json_string = json_string .. "\"" .. escapedValue .. "\""
  68. elseif nodeType == "Number" or nodeType == "Bool" then
  69. json_string = json_string .. value
  70. elseif nodeType == "Null" then
  71. json_string = json_string .. "null"
  72. else
  73. -- Para outros tipos, como Object ou Array, você precisará lidar com eles recursivamente
  74. json_string = json_string .. "null"
  75. end
  76.  
  77. i = i + 1
  78. end
  79. json_string = json_string .. "}"
  80. return json_string
  81. end
  82.  
  83. -- Função para enviar mensagens JSON via WebSocket (recebe objeto JSON)
  84. local function send_json(socket, hJSON)
  85. if not hJSON then
  86. ELAN_Trace("Erro: Objeto JSON é nil.")
  87. return
  88. end
  89.  
  90. local json_string = table_to_json(hJSON)
  91. if not json_string then
  92. ELAN_Trace("Erro ao serializar objeto JSON para string.")
  93. ELAN_DeleteJSONMsg(hJSON)
  94. return
  95. end
  96.  
  97. -- Deleta a estrutura JSON após a serialização
  98. ELAN_DeleteJSONMsg(hJSON)
  99.  
  100. ELAN_Trace("Enviando objeto JSON via WebSocket: " .. json_string)
  101. local success = ELAN_SendTCP(socket, json_string, string.len(json_string))
  102. if success == -1 then
  103. ELAN_Trace("Erro ao enviar mensagem JSON via WebSocket")
  104. end
  105. end
  106.  
  107. -- Função para gerar uma chave Base64 aleatória
  108. local function generate_base64_key(length)
  109. local random_data = ""
  110. for i = 1, length do
  111. random_data = random_data .. string.char(math.random(0, 255))
  112. end
  113. local base64_key = ELAN_Base64Codec(random_data, "ENCODE")
  114. return base64_key
  115. end
  116.  
  117. -- Monta a mensagem de upgrade HTTP
  118. local function build_http_upgrade_message(host)
  119. local key = generate_base64_key(16)
  120. local upgrade_message = "GET /api/websocket HTTP/1.1\r\n"
  121. .. "Host: " .. host .. "\r\n"
  122. .. "Upgrade: websocket\r\n"
  123. .. "Connection: Upgrade\r\n"
  124. .. "Sec-WebSocket-Key: " .. key .. "\r\n"
  125. .. "Sec-WebSocket-Version: 13\r\n\r\n"
  126. return upgrade_message
  127. end
  128.  
  129. -- Função de inicialização
  130. function EDRV_Init()
  131. ELAN_Trace("Driver HomeAssistantLighting inicializado")
  132.  
  133. -- Obtém as configurações do Home Assistant
  134. local haConfig = getHAConfig()
  135. if not haConfig then
  136. ELAN_Trace("Configurações do Home Assistant inválidas. Abortando.")
  137. return
  138. end
  139.  
  140. ha_host = haConfig.host
  141. ha_port = haConfig.port
  142. ha_token = haConfig.token
  143.  
  144. socket_id = ELAN_CreateTCPClientSocket(ha_host, ha_port)
  145.  
  146. if socket_id <= 0 then
  147. ELAN_Trace("Erro ao criar socket TCP: " .. socket_id)
  148. return
  149. end
  150.  
  151. local connected = ELAN_ConnectTCPSocketAsync(socket_id, 5000)
  152. if not connected then
  153. ELAN_Trace("Erro ao iniciar conexão TCP.")
  154. ELAN_CloseSocket(socket_id)
  155. return
  156. end
  157. end
  158.  
  159. -- Notificação de conexão TCP assíncrona
  160. function EDRV_OnTCPAsyncConnect(socket, success)
  161. if socket == socket_id and success then
  162. ELAN_Trace("Conexão TCP estabelecida com sucesso.")
  163. local http_upgrade_message = build_http_upgrade_message(ha_host)
  164. ELAN_SendHTTP(socket_id, http_upgrade_message, "", false)
  165. else
  166. ELAN_Trace("Falha ao conectar TCP.")
  167. ELAN_CloseSocket(socket_id)
  168. end
  169. end
  170.  
  171. -- Recebe dados do WebSocket
  172. function EDRV_RecvTCP(socket, nDataBytes, message)
  173. if socket == socket_id then
  174. ELAN_Trace("Dados recebidos do WebSocket: " .. message)
  175.  
  176. -- Verifica se a autenticação é necessária e ainda não foi enviada
  177. if message:find("auth_required") and not auth_sent then
  178. ELAN_Trace("Autenticação requerida, enviando credenciais...")
  179.  
  180. -- Cria a mensagem de autenticação
  181. local hAuthMessage = ELAN_CreateJSONMsg()
  182. ELAN_AddJSONKeyValuePair(hAuthMessage, hAuthMessage, "type", "auth")
  183. ELAN_AddJSONKeyValuePair(hAuthMessage, hAuthMessage, "access_token", ha_token)
  184. send_json(socket_id, hAuthMessage)
  185.  
  186. auth_sent = true
  187. elseif message:find("auth_ok") then
  188. ELAN_Trace("Autenticação bem-sucedida.")
  189.  
  190. -- Continua com outros comandos, por exemplo, pegar entidades
  191. local hGetStatesMessage = ELAN_CreateJSONMsg()
  192. ELAN_AddJSONKeyValuePair(hGetStatesMessage, hGetStatesMessage, "id", 1)
  193. ELAN_AddJSONKeyValuePair(hGetStatesMessage, hGetStatesMessage, "type", "get_states")
  194. send_json(socket_id, hGetStatesMessage)
  195. elseif message:find("auth_invalid") then
  196. ELAN_Trace("Autenticação inválida.")
  197. ELAN_CloseSocket(socket_id)
  198. elseif message:find("result") then
  199. ELAN_Trace("Resultado recebido do Home Assistant.")
  200. end
  201. end
  202. end
  203.  
  204. -- Função para lidar com desconexão TCP
  205. function EDRV_OnTCPDisconnect(socket)
  206. if socket == socket_id then
  207. ELAN_Trace("Conexão TCP desconectada.")
  208. ELAN_CloseSocket(socket_id)
  209. socket_id = nil
  210. auth_sent = false
  211. end
  212. end
  213.  
  214. function EDRV_ClosedWebSocket(socket, message)
  215. if socket == socket_id then
  216. ELAN_Trace("Conexão WebSocket fechada: " .. message)
  217. ELAN_CloseSocket(socket_id)
  218. socket_id = nil
  219. auth_sent = false
  220. end
  221. end
  222.  
Success #stdin #stdout 0.01s 5288KB
stdin
Standard input is empty
stdout
Standard output is empty