Update device state in 'while loop'

Posted on
Wed Apr 03, 2024 9:10 am
CliveS offline
Posts: 771
Joined: Jan 10, 2016
Location: Medomsley, County Durham, UK

Update device state in 'while loop'

I am trying to break out of a while loop when a contact sensor changes but the script obviously only knows the state at the start. Is there a way of updating it inside the loop?

Code: Select all

# Import the time module for time-related functions
import time

# Initialize the loop counter
count_loop = 0

# Get the device by its ID
dev = indigo.devices[683155862]  # "Z Aqara P1 door & window contact"

# Log the current state of the onOffState
indigo.server.log(f"Current onOffState: {dev.states['onOffState']}")

# Pause execution for 2 seconds
time.sleep(2)

# Retrieve the initial state of the onOffState
doorStatus = dev.states["onOffState"]

# Loop until the doorStatus becomes True or count_loop reaches 10
while not doorStatus and count_loop < 10: 
    # Log the current iteration number and the onOffState
    indigo.server.log(f"Loop iteration {count_loop}, onOffState: {doorStatus}")
   
    # Increment the loop counter
    count_loop += 1
   
    # Pause execution for 2 seconds
    time.sleep(2)
   
    # Update the doorStatus with the current state
    doorStatus = dev.states["onOffState"]

# Log a message indicating the end of the loop and the final value of count_loop
indigo.server.log(f"Loop finished, count_loop is {count_loop}")



CliveS

Indigo 2023.2.0 : macOS Ventura 13.6.3 : Mac Mini M2 : 8‑core CPU and 10‑core GPU : 8 GB : 256GB SSD
----------------------------------------------------------------------------------
The best way to get the right answer on the Internet is not to ask a question, it's to post the wrong answer

Posted on
Wed Apr 03, 2024 11:10 am
FlyingDiver offline
User avatar
Posts: 7226
Joined: Jun 07, 2014
Location: Southwest Florida, USA

Re: Update device state in 'while loop'

You have to re-fetch the dev object inside the loop, then compare the current state to the saved state.

joe (aka FlyingDiver)
my plugins: http://forums.indigodomo.com/viewforum.php?f=177

Posted on
Wed Apr 03, 2024 11:42 am
CliveS offline
Posts: 771
Joined: Jan 10, 2016
Location: Medomsley, County Durham, UK

Re: Update device state in 'while loop'

Joe, can you give a pointer to the way of doing that in the Indigo documentation please.

CliveS

Indigo 2023.2.0 : macOS Ventura 13.6.3 : Mac Mini M2 : 8‑core CPU and 10‑core GPU : 8 GB : 256GB SSD
----------------------------------------------------------------------------------
The best way to get the right answer on the Internet is not to ask a question, it's to post the wrong answer

Posted on
Wed Apr 03, 2024 11:46 am
FlyingDiver offline
User avatar
Posts: 7226
Joined: Jun 07, 2014
Location: Southwest Florida, USA

Re: Update device state in 'while loop'

You're fetching a copy of the device object when you do "dev = indigo.devices[683155862]", which is the only Indigo specific thing here.

Code: Select all
# Initialize the loop counter
count_loop = 0

# Get the device by its ID
dev = indigo.devices[683155862]  # "Z Aqara P1 door & window contact"

# Retrieve the initial state of the onOffState
startDoorStatus = dev.states["onOffState"]

# Log the current state of the onOffState
indigo.server.log(f"Current onOffState:  {startDoorStatus}")

# Loop until the doorStatus changes or count_loop reaches 10
while count_loop < 10:
   
    # Pause execution for 2 seconds
    time.sleep(2)

    dev = indigo.devices[683155862]  # "Z Aqara P1 door & window contact"

    # Log the current iteration number and the onOffState
    indigo.server.log(f"Loop iteration {count_loop}, onOffState: { dev.states["onOffState"]}")

    # Check the doorStatus
    if startDoorStatus != dev.states["onOffState"]:
       break
   
    # Increment the loop counter
    count_loop += 1

# Log a message indicating the end of the loop and the final value of count_loop
indigo.server.log(f"Loop finished, count_loop is {count_loop}")

joe (aka FlyingDiver)
my plugins: http://forums.indigodomo.com/viewforum.php?f=177

Posted on
Wed Apr 03, 2024 12:14 pm
CliveS offline
Posts: 771
Joined: Jan 10, 2016
Location: Medomsley, County Durham, UK

Re: Update device state in 'while loop'

That works a treat, I see what I was doing wrong now and another one for my 'python howto file'
Thank you very much.

CliveS

Indigo 2023.2.0 : macOS Ventura 13.6.3 : Mac Mini M2 : 8‑core CPU and 10‑core GPU : 8 GB : 256GB SSD
----------------------------------------------------------------------------------
The best way to get the right answer on the Internet is not to ask a question, it's to post the wrong answer

Posted on
Wed Apr 03, 2024 1:26 pm
matt (support) offline
Site Admin
User avatar
Posts: 21417
Joined: Jan 27, 2003
Location: Texas

Re: Update device state in 'while loop'

A slightly more efficient way to update the device instance is with this API (compared to fetching an entirely new instance from the server):

Code: Select all
dev.refreshFromServer()

Image

Posted on
Wed Apr 03, 2024 2:40 pm
CliveS offline
Posts: 771
Joined: Jan 10, 2016
Location: Medomsley, County Durham, UK

Re: Update device state in 'while loop'

Thanks Matt, I will try that as well, a good learning curve, and another line in the ‘python howto file’.

CliveS

Indigo 2023.2.0 : macOS Ventura 13.6.3 : Mac Mini M2 : 8‑core CPU and 10‑core GPU : 8 GB : 256GB SSD
----------------------------------------------------------------------------------
The best way to get the right answer on the Internet is not to ask a question, it's to post the wrong answer

Posted on
Wed Apr 03, 2024 2:49 pm
FlyingDiver offline
User avatar
Posts: 7226
Joined: Jun 07, 2014
Location: Southwest Florida, USA

Re: Update device state in 'while loop'

matt (support) wrote:
A slightly more efficient way to update the device instance is with this API (compared to fetching an entirely new instance from the server):

Code: Select all
dev.refreshFromServer()


I should have remembered that one.

joe (aka FlyingDiver)
my plugins: http://forums.indigodomo.com/viewforum.php?f=177

Posted on
Sat Apr 06, 2024 2:29 am
kw123 offline
User avatar
Posts: 8366
Joined: May 12, 2013
Location: Dallas, TX

Re: Update device state in 'while loop'

Q: how does this work? Does indigo remember the last fetch? And then gets the new data only?


Sent from my iPhone using Tapatalk

Posted on
Sun Apr 07, 2024 2:13 pm
matt (support) offline
Site Admin
User avatar
Posts: 21417
Joined: Jan 27, 2003
Location: Texas

Re: Update device state in 'while loop'

It fetches all the current device states and properties, replacing those attributes in the instance. I don't recall what happens if the device class changes (say from a dimmer to a thermostat), so no promises that will be handled correctly or gracefully.

Image

Posted on
Wed Apr 17, 2024 9:30 am
kw123 offline
User avatar
Posts: 8366
Joined: May 12, 2013
Location: Dallas, TX

Re: Update device state in 'while loop'

Added this code to the beginning of runConcurrentThread(self) ( before the main loop) in one of my plugins to check what the effect of dev.refreshFromServer() vs dev = indigo.devices{} ds:
Code: Select all
      devId = 1667343748
      tStart = time.time()
      for ii in range(1000):
         dev = indigo.devices[devId]
         dev.updateStateOnServer("hardwareVendor",str(time.time())) # dummy state update of an empty unused state
      indigo.server.log( "after 1000 iterations with new dev=indigo.devices[] dt = {:.5f} ".format(time.time() - tStart))
      self.sleep(1)
      
      tStart = time.time()
      dev = indigo.devices[devId]
      for ii in range(1000):
         dev.updateStateOnServer("hardwareVendor",str(time.time()))# dummy state update of an empty unused state
         dev.refreshFromServer()
      indigo.server.log( "after 1000 iterations with dev.refreshFromServer(): dt = {:.5f} ".format(time.time() - tStart))

i got:
Code: Select all
after 1000 iterations with new dev=indigo.devices[] dt = 0.79437
after 1000 iterations with dev.refreshFromServer(): dt = 0.89304   


dev.refreshFromServer() seems to be a tiny bit slower than dev = indigo.devices[devId] ... or am I looking at some caching effect?

and on a side note:
Code: Select all
 
      tStart = time.time()
      dev = indigo.devices[devId]
      for ii in range(1000):
         dev.updateStateOnServer("hardwareVendor",str(time.time()))
      indigo.server.log( "dev.updateStateOnServer after 1000 iterations  = {:.5f} ".format(time.time() - tStart))
gives:
dev.updateStateOnServer after 1000 iterations dt = 0.00636


Karl

Posted on
Wed Apr 17, 2024 10:45 am
FlyingDiver offline
User avatar
Posts: 7226
Joined: Jun 07, 2014
Location: Southwest Florida, USA

Re: Update device state in 'while loop'

You're only measuring the time spent in the plugin, not the load on the server.

joe (aka FlyingDiver)
my plugins: http://forums.indigodomo.com/viewforum.php?f=177

Posted on
Wed Apr 17, 2024 11:43 am
kw123 offline
User avatar
Posts: 8366
Joined: May 12, 2013
Location: Dallas, TX

Re: Update device state in 'while loop'

ok got that,
2. test with a larger loop (1k--> 20k) to check the cpu time manually w activity monitor

Code: Select all
      devId = 1667343748
      indigo.server.log( "starting w 1 20000 loop , check server load")
      self.sleep(2)
      tStart = time.time()
      for ii in range(20000):
         dev = indigo.devices[devId]
         dev.updateStateOnServer("hardwareVendor",str(time.time())) # dummy state update of an empty unused state
      indigo.server.log( "after 20000 iterations with new indigo.devices[] dt = {:.5f} ".format(time.time() - tStart))

      time.sleep(50)  ## let the cpu indicator cool down

      indigo.server.log( "starting w 2. 20000 loop , check server load")
      self.sleep(2)
      tStart = time.time()
      dev = indigo.devices[devId]
      for ii in range(20000):
         dev.updateStateOnServer("hardwareVendor",str(time.time())) # dummy state update of an empty unused state
         dev.refreshFromServer()
      indigo.server.log( "after 20000 iterations with new refreshFromServer dt = {:.5f} ".format(time.time() - tStart))


gives
starting w 1 20000 loop , check server load
after 20000 iterations with new indigo.devices[] dt = 16.17746
starting w 2. 20000 loop , check server load
after 20000 iterations with new refreshFromServer dt = 16.31658

in both cases CPU load:
indigo 2023.2 up to 120%
indigo server 50%
the plugin is around 1-4%

it looks as if in both cases the execution takes ~ 16 secs for 20,000 iterations and the CPU load is about the same ( kind of in overload @ 120% for indigo client, should not be the dev.updateStateOnServer as that alone w/o the dev =indigodevcies[] is done in 0.1 secs)

next step would be to measure the total cpu consumed ( within the plugin ) before and after loop for indigo client and server processes

Posted on
Wed Apr 17, 2024 2:22 pm
kw123 offline
User avatar
Posts: 8366
Joined: May 12, 2013
Location: Dallas, TX

Re: Update device state in 'while loop'

Using the same loops as before , just adding a call to
/bin/ps -ef | grep 'Contents/MacOS/Indigo 2023.2' | grep -v grep"
and
/bin/ps -ef | grep 'IndigoServer' | grep -v grep
before and after loop

that returns something like:
...... 29:53.49 Applications/Indigo', '2023.2.app/Contents/MacOS/Indigo', '2023.2']
...... 30:11.51 Applications/Indigo', '2023.2.app/Contents/MacOS/Indigo', '2023.2']
and the delta 30:11.51 - 29:53.49 should be the consumed CPU time


gives:
Code: Select all
            indigo.devices[]  vs     refreshFromServer
indigo client:   18.02         vs      21.54 secs
indigo server:    6.87         vs      10.59 secs

loop with
Code: Select all
indigo.devices[]    --> ~24 secs consumed CPU by indigo server and indigo client
refreshFromServer   --> ~31 secs consumed CPU by indigo server and indigo client


in Summary
if this is correct the loop with 20,000 calls
w dev=indigo.devices[] uses 7 secs LESS CPU that the loop with dev.refreshFromServer()

Karl

Posted on
Thu Apr 18, 2024 11:08 am
matt (support) offline
Site Admin
User avatar
Posts: 21417
Joined: Jan 27, 2003
Location: Texas

Re: Update device state in 'while loop'

Hi Karl,

Interesting performance numbers. I would have expected the opposite. I just looked at the python API / glue code and I would expect that dev.refreshFromServer would be the same speed or a bit faster than requesting a new device instance from the server.. I agree with your data though, so there must be some overhead I'm not seeing. I'd probably still recommend using dev.refreshFromServer on the chance that some day we add some optimizations to it (and it isn't horribly slower), but that is just a personal preference.

Image

Page 1 of 1

Who is online

Users browsing this forum: No registered users and 11 guests