This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm whether you accept or reject these cookies being set.

Some assistance needed to improve HTTP call efficiency
#1
Hi,
I am running some scripts in my LM (a Schneider branded one for the CBUS protocol), and am using it to control a number of Sonoff relays via HTTP. My command to each device works perfect, I have an event script on each Group address I want to control a given Sonoff. Any time I activate my Cbus Group, the Sonoff follows it, as needed.
My Sonoff’s also have local switches connected to their GPIO pins, and if a user presses one of the physical buttons on the Sonoff, the Group addresses ‘Status’ is then out of sync. So, I then created a resident script to run every 2 seconds to poll all the Sonoffs , retrieve their current status, and then update the Group address status if needed, putting things back in sync.  I have about 10 Sonoffs, and I poll each one in a For loop, so it’s not the quickest… Also, unfortunately, when I fix the Group address Status/State with my resident script, it triggers another event script on that GA, which is not really necessary and is just consuming resources…
I will post an abbreviation of my code here, but would love to get some advice on a more streamlined way to do the feedback part, without consuming too much CPU etc. 
Also, my resident script runs two-second intervals, but I could extend this out to 10 or 15 if needed. But still, would like to keep it as snappy as possible...

Event Script
Code:
-- Enter IP Address of Tasmota Device
IPaddr = '192.168.0.212'
-- Enter Tasmota Channel Number
CH = 1
-- Enter Group Number of CBUS GA
GA = 100 -- (This is the Garage Main Lights)

function send_tasmota_http_command(ip, ch, state)
   http = require('socket.http')
   res, err = http.request({
      url = 'http://' .. ip .. '/cm?cmnd=Power' .. ch .. '%20' .. state,
    method = 'GET',
  })
end

storage.set('Tasmota_Update_Event_Blocker', true)

if (GetLightingState(GA) == true) then
  send_tasmota_http_command(IPaddr, CH, 'On')
elseif (GetLightingState(GA) == false)  then
  send_tasmota_http_command(IPaddr, CH, 'Off')
end

os.sleep(1)
storage.set('Tasmota_Update_Event_Blocker', false)



Resident Script



Code:
-- Enter IP Address of Tasmota Device
IPaddr = '192.168.0.212' -- (This is the Garage Main Light)
-- Enter Tasmota Channel Number
CH = 1
-- Enter Group Number of CBUS GA
GA = 100 -- (This is the Garage Main Light)

-- In reality this function is in a User Library but shown here for simplicity

-- A function to request status feedback from a Tasmota Device
function Request_tasmota_http_get_feedback(ip, CH)
   http = require('socket.http')
   ltn12 = require('ltn12')
   require('json')
   sink = {}
   res, err = http.request({
      url = 'http://' .. ip .. '/cm?cmnd=Power' ..CH,
      method = 'GET',
      headers = {["Content-Type"] = "application/json"},
      sink = ltn12.sink.table(sink)
  })

  if sink then
    return table.concat(sink)
  else
    return nil, err
  end
end

-- Again in reality, the remainder of this code runs in a for loop, iterating through an array of approx 10 devices
-- The array is a LUA table containing the IP, Sonoff Channel number and Group address of each device to be polled...

  reply = Request_tasmota_http_get_feedback(IPaddr, CH) -- Returns an array
  -- Walk through array, load into a LUA table
  data = {}
  for val in string.gmatch(reply, "\"(%a+)\"") do -- split the array on double quotes (needs to be escaped with \ )
          table.insert(data, val)
       end
  --log(data) -- Log the array if needed, to find the correct index
  --log("Resident: Light at Address : " .. GA .. " is " .. data[2])
    
Update_Blocked = storage.get('Tasmota_Update_Event_Blocker', false) -- get unblocker status, with default of false if not set
--log("Update_Blocked is : ", Update_Blocked)

-- Fix The feeback, if allowed
if (data[2] == 'ON' and (GetLightingState(GA) == false) and (Update_Blocked == false)) then
    SetLightingState(GA, true)
elseif (data[2] == 'OFF' and (GetLightingState(GA) == true) and (Update_Blocked == false)) then
    SetLightingState(GA, false)
end



Would appreciate any suggestions on how to make this process more efficient/quicker. It works ok most of the time, but sometimes the scripts seem to step on each other, or the feedback is still out of sync. Particularly if there is a lot of persistent and quick pressing of the buttons (kids!). - Thanks.
Reply
#2
Have you considered using MQTT (https://tasmota.github.io/docs/MQTT/) for this? It looks like you can configure status updates to be published to MQTT automatically so polling is not needed.

You can also check event.sender value in event scripts. It will tell you who triggered the event.
Code:
-- do nothing if triggered by a resident script
if event.sender == 'sr' then
  return
end
See this post for a list of possible senders: https://forum.logicmachine.net/showthrea...3#pid19193
Reply
#3
Thanks, Admin. I knew about the MQTT possibilities but was trying to avoid it if possible. I didn't want to set up another server to run MQTT for the sake of some feedback on my visualizations. I can't use any of the new LM firmware either (which has MQTT on board), as my device is a SHAC from Schneider, not a standard-issue LM.

Anyways, following your tip, I eliminated a lot of bogus events and have reached an acceptable solution and level of performance. Checking for an 'sr' event didn't actually work for me, but after a bit of logging and debugging, I found the correct events for my device that I needed to act on, or ignore, as needed..

I put this at the start of each individual Event script, and now it is no longer re-triggered by my resident script..
Code:
log ("Event Sender : ", event.sender) -- Inspect the sender - Returns 'cb' if a real event from cbus bus or 'cl' if it came from my resident script
-- Do nothing if this event has been caused by a 'cl' event
if event.sender == 'cl' then
  log ("Bailing out...") 
  return  -- Script exits here, the rest is ignored
end

Thank you!
Reply


Forum Jump: