pylutron_caseta help please with Lutron buttons - python

I'm using the pylutron_caseta python package for use with Lutron devices. At this stage I'm trying to listen for button presses. I'm able to pair with the bridge and get the buttons, but I'm unable to listen for button presses. Here's my code:
import asyncio
from pylutron_caseta.smartbridge import Smartbridge
from pylutron_caseta.pairing import async_pair
from os.path import exists
bridgeIp = "192.168.1.40"
async def pair(host: str):
def _ready():
print("Press the small black button on the back of the bridge.")
data = await async_pair(host, _ready)
with open("caseta-bridge.crt", "w") as cacert:
cacert.write(data["ca"])
with open("caseta.crt", "w") as cert:
cert.write(data["cert"])
with open("caseta.key", "w") as key:
key.write(data["key"])
print(f"Successfully paired with {data['version']}")
async def registerButton(bridge,button_id):
print("Press the small button on the button device.")
def printThis(x):
print(x)
async def connect():
bridge = Smartbridge.create_tls(bridgeIp, "caseta.key", "caseta.crt", "caseta-bridge.crt")
await bridge.connect()
buttons = bridge.get_buttons()
print (buttons)
for b in buttons:
print (b)
loopListen = asyncio.get_event_loop()
asyncio.ensure_future(listen(bridge,int(b)))
loopListen.run_forever()
async def listen(bridge,_buttonID):
while True:
bridge.add_button_subscriber(str(_buttonID), printThis)
#Program
if exists("caseta-bridge.crt"):
print("found pair files")
loop = asyncio.get_event_loop()
loop.run_until_complete(connect())
else:
loop = asyncio.get_event_loop()
loop.run_until_complete(pair(bridgeIp))
loop = asyncio.get_event_loop()
loop.run_until_complete(connect())
I expect that when I press a button on the Lutron Pico remote that I get some sort of response printed. I get nothing printed. I'm guessing I have the "listen" function incorrect, just not sure how.
Any help is appreciated!

I was able to make my Lutron Pico remotes work with a node js module called lutronpro found here: https://www.npmjs.com/package/lutronpro.
I had to upgrade to the pro lutron controller module to make it work. I would prefer to do this in Python, but at least I could get this to work, and know when a remote button was pressed and from there I could call a python web service to do the rest. I ultimately just made it start up this program on boot on my raspberry pi, and now I use my pico remote to control almost anything in the hous

Related

tkinter freezing when press button with libraries like tiktoklive

I face an issue and I want to understand why this problem happens and how to solve this problem. I know a lot of questions on stack overflow that talk about tkinter freeze when button pressed I saw many solutions but it is not working for me and I want some help to understand how to solve this problem, I work on some app using tkinter I trying use libraries like TikTokLive to learn new something and I tried to make a button that when pressed gives some information I tried threading but not working and tried to see about use queue and I understand the queue and I saw solutions like use multiprocess but nothing works for me so I thought that problem happens because of the tiktoklive library may be because we use async programming so I made some search and saw solution but not working, I want to some help to understand more how to solve this problem.
Sample code below:
from tkinter import *
root = Tk()
root.geometry("300x300")
get_information = Button(text="get", font='normal 30 bold', command=lambda: connect_with_tiktok_live())
get_information.pack()
def connect_with_tiktok_live():
# dependencies
import TikTokLive.types.events
from TikTokLive import TikTokLiveClient
from TikTokLive.types.events import ConnectEvent
username = "put the username of tiktok live"
# Instantiate the client with the user's username
client: TikTokLiveClient = TikTokLiveClient(
unique_id=username, **({
"process_initial_data": False,
"enable_extended_gift_info": True,
}))
#client.on('connect')
async def on_connect(_: ConnectEvent):
print("Connected to Room ID: ", client.room_id)
# Run the client and block the main thread
# await client.start() to run non-blocking
try:
return client.run()
except FailedConnection: # if live is ended
print('finished')
mainloop()
gif problrm:
some links solution not working for me
How can I prevent a tkinter Gui from freezing while an async task is running?
python running task in the background while allowing tkinter to be active
Tkinter window says (not responding) but code is running
How to easily avoid Tkinter freezing?
How to run a function in the background of tkinter
Tkinter: How to use threads to preventing main event loop from "freezing"
You can use multithreading here using threading.Thread method.
from tkinter import *
from threading import Thread
root = Tk()
root.geometry("300x300")
get_information = Button(text="get", font='normal 30 bold', command= lambda:Thread(target=connect_with_tiktok_live).start())
get_information.pack()
def connect_with_tiktok_live():
# dependencies
import TikTokLive.types.events
from TikTokLive import TikTokLiveClient
from TikTokLive.types.events import ConnectEvent
username = "put the username of tiktok live"
# Instantiate the client with the user's username
client: TikTokLiveClient = TikTokLiveClient(
unique_id=username, **({
"process_initial_data": False,
"enable_extended_gift_info": True,
}))
#client.on('connect')
async def on_connect(_: ConnectEvent):
print("Connected to Room ID: ", client.room_id)
# Run the client and block the main thread
# await client.start() to run non-blocking
try:
return client.run()
except FailedConnection: # if live is ended
print('finished')
mainloop()

How to stop continuous_threading in python

I am working on a project, where I have to read values from serial port and display them on tkinter GUI. I am using continous threading module of python. I am using a continous thread to read the data on serial port continously after every 0.5s, but now i want to stop this continous thread. So how should I stop it ?
This is the function which I am calling when a checkbutton is presssed
def scan():
print("in scan")
btn1_state = var1.get()
print("Scan: %d"%btn1_state)
t1 = continuous_threading.PeriodicThread(0.5, readserial)
if(btn1_state == 1):
t1.start()
else:
print("entered else ")
t1.stop() #I am using stop() but the thread doesn't stop
Please Help
The problem is likely that you are using a blocking read function in your readserial function. It needs a timeout. I can reproduce with this code:
import time
import continuous_threading
time_list = []
def save_time():
while True:
time.sleep(1)
time_list.append(time.time())
th = continuous_threading.PeriodicThread(0.5, save_time)
th.start()
time.sleep(4)
th.join()
print(time_list)
This never exits.
Modified from the examples.
Since continuous_threading expects it's event loop to be in control, it never gets to the stop event.

Waiting for user input when controlling 3rd party application via python script

I am writing a script intended to be used by members of a project team. As part of the script, I am launching a 3rd party proprietary application run through Citrix. I am going to use the script mostly to send keys to this application, but the first step once it launches is for the user to log in.
Because I would like the user to log in while the script is running, rather than asking for user/pass from some kind of GUI input earlier, and because the time it takes Citrix to launch varies, I would like to include some kind of logic that detects when the user has logged in and then resume the script from there, rather than including an obnoxiously long implicit wait or risking the script timing out.
Is there a way to detect user keystrokes using win32com.client (or to detect a change in state of the application itself)? See below for the relevant code to launch the app:
import win32com.client
shell = win32com.client.Dispatch("WScript.Shell")
shell.Run('C:\Citrix\[rest of path])
EDIT:
Per Vasily's suggestion in the comments below, I attempted to adapt the "hook and listen" code to my scenario, but was unsuccessful. When I launch my file, I don't even get an exception message in my terminal, I get a Windows pop-up that says Python encountered a problem and needs to quit.
This is how I adapted it:
#[omitting import lines for brevity]
def on_timer():
"""Callback by timer out"""
win32api.PostThreadMessage(main_thread_id, win32con.WM_QUIT, 0, 0);
def on_event(args):
"""Callback for keyboard and mouse events"""
if isinstance(args, KeyboardEvent):
for i in range(1,100):
time.sleep(1)
if args.pressed_key == 'Lcontrol':
break
def init():
hk = Hook()
hk.handler = on_event
main_thread_id = win32api.GetCurrentThreadId()
t = Timer(55.0, on_timer) # Quit after 55 seconds
t.start()
hk.hook(keyboard=True, mouse=True)
At the point when the 3rd party Citrix app begins to launch in my main script, I call hookandlisten.init().
As a reminder, my goal is to wait until the user sends a certain keystroke (here I chose Control) before proceeding with the rest of the main script.
Solved this by eliminating the timer and unhooking the keyboard upon the correct keystroke:
import win32api
import win32con
from pywinauto.win32_hooks import Hook
from pywinauto.win32_hooks import KeyboardEvent
from pywinauto.win32_hooks import MouseEvent
def on_event(args):
"""Callback for keyboard and mouse events"""
if isinstance(args, KeyboardEvent):
if args.current_key == 'Lcontrol' and args.event_type == 'key down':
print("Success")
hk.unhook_keyboard()
return
def init():
hk.handler = on_event
hk.hook(keyboard=True, mouse=False)
hk = Hook()

python wget library not returning if internet goes down for some times. How can I return with error if Internet is down?

I have below code to download a file inside a loop,
import wget
try:
wget.download(url)
except:
pass
But if the Internet goes down, it doesn't return!
So my whole loop is stuck.
I want to repeat the same download if internet goes down. So I wanna know does any error happen.
How can i mitigate this?
One simple solution is to move your download code to a thread and make it a separate process which can be interrupted.
You can use python Thread and Timer module to achieve it.
from threading import Thread, Timer
from functools import partial
import time
import urllib
def check_connectivity(t):
try:
urllib.request.urlopen("http://google.com", timeout=2)
except Exception as e:
t._Thread__stop()
class Download(Thread):
def run(self):
print("Trying to download file....")
con = partial(check_connectivity, self)
while True:
t = Timer(5, con) # Checks the connectivity every 5 second or less.
t.start()
# your download code....
def main():
down = Download()
down.start()
down.join()
You code move your main download loop inside the thread's run method. And start a timer inside which listens for the network connectivity.

Listening for a threading Event in python

first time SO user, please excuse any etiquette errors. I'm trying to implement a multithreaded program in python and am having troubles. This is no doubt due to a lack of understanding of how threading is implemented, but hopefully you can help me figure it out.
I have a basic program that continually listens for messages on a serial port and can then print/save/process/etc them, which works fine. It basically looks like this:
import serial
def main():
usb = serial.Serial('/dev/cu.usbserial-A603UBRB', 57600) #open serial w\ baud rate
while True:
line = usb.readline()
print(line)
However what I want to do is continually listen for the messages on a serial port, but not necessarily do anything with them. This should run in the background, and meanwhile in the foreground I want to have some kind of interface where the user can command the program to read/use/save these data for a while and then stop again.
So I created the following code:
import time
import serial
import threading
# this runs in the background constantly, reading the serial bus input
class serial_listener(threading.Thread):
def __init__(self, line, event):
super(serial_listener, self).__init__()
self.event = threading.Event()
self.line = ''
self.usb = serial.Serial('/dev/cu.usbserial-A603UBRB', 57600)
def run(self):
while True:
self.line = self.usb.readline()
self.event.set()
self.event.clear()
time.sleep(0.01)
# this lets the user command the software to record several values from serial
class record_data(threading.Thread):
def __init__(self):
super(record_data, self).__init__()
self.line = ''
self.event = threading.Event()
self.ser = serial_listener(self.line,self.event)
self.ser.start() #run thread
def run(self):
while(True):
user_input = raw_input('Record data: ')
if user_input == 'r':
event_counter = 0
while(event_counter < 16):
self.event.wait()
print(self.line)
event_counter += 1
# this is going to be the mother function
def main():
dat = record_data()
dat.start()
# this makes the code behave like C code.
if __name__ == '__main__':
main()
It compiles and runs, but when I order the program to record by typing r into the CLI, nothing happens. It doesn't seem to be receiving any events.
Any clues how to make this work? Workarounds are also fine, the only thing is that I can't constantly open and close the serial interface, it has to remain open the whole time, or else the device stops working until un/replugged.
Instead of using multiple threads, I would suggest using multiple processes. When you use threads, you have to think about the global interpreter lock. So you either listen to events or do something in your main thread. Both at the same time will not work.
When using multiple processes I would then use a queue to forward the events from your watchdog that you would like to handle. Or you could code your own event handler. Here you can find an example for multiprocess event handlers

Categories