Closed sharon-elihis closed 3 weeks ago
Hi @sharon-elihis
I used the following example and did not see the 'LeakyBucket' object has no attribute 'add_dropp' error.
Are you on the latest SDK 2.7.3?
from sinric import SinricPro, SinricProConstants
import asyncio
from asyncio import sleep
APP_KEY = ""
APP_SECRET = ""
THERMOSTAT_ID = ""
def power_state(device_id, state):
print('device_id: {} state: {}'.format(device_id, state))
return True, state
def target_temperature(device_id, temperature):
print('device_id: {} set temperature: {}'.format(device_id, temperature))
return True, temperature
def set_thermostate_mode(device_id, thermostat_mode):
print('device_id: {} set thermostat mode: {}'.format(device_id, thermostat_mode))
return True, thermostat_mode
def mode_value(device_id, mode_value):
print(device_id, mode_value)
return True, mode_value
async def events():
while True:
client.event_handler.raise_event(THERMOSTAT_ID, SinricProConstants.SET_THERMOSTAT_MODE, data= { SinricProConstants.MODE : 'COOL'})
# client.event_handler.raise_event(THERMOSTAT_ID, SinricProConstants.SET_POWER_STATE, data= {SinricProConstants.STATE: SinricProConstants.POWER_STATE_OFF})
# client.event_handler.raise_event(THERMOSTAT_ID, SinricProConstants.CURRENT_TEMPERATURE, data={'humidity': 75.3, 'temperature': 24})
# Server will trottle / block IPs sending events too often.
await sleep(60)
callbacks = {
SinricProConstants.SET_POWER_STATE: power_state,
SinricProConstants.TARGET_TEMPERATURE: target_temperature,
SinricProConstants.SET_THERMOSTAT_MODE: set_thermostate_mode
}
if __name__ == '__main__':
loop = asyncio.get_event_loop()
client = SinricPro(APP_KEY, [THERMOSTAT_ID], callbacks, event_callbacks=events,
enable_log=True, restore_states=False, secret_key=APP_SECRET)
loop.run_until_complete(client.connect())
SinricProConstants.SET_MODE has no effect.
I will release a new version with the modes in the constant py.
Hi @kakopappa Thank you for the very fast reply and screenshots.
Yes, I am using 2.7.3
I took your example and only changed those 3 ids and it didn't work for me. I didn't get leakybucket error - that was because I did something stupid on my end. but it just didn't do the event, and again it popped up a message that my device is online - every time I run it.
But if I comment out that event and uncomment the CURRENT_TEMPERATURE event it does work, and that "device is online" message does not popup.
I'm using python 3.12.5, not sure if it matters.
Is it possible that to share your code without credentials
It's a full copy-paste from the example code you provided, I only changed the 3 ids from sinric import SinricPro, SinricProConstants import asyncio from asyncio import sleep
APP_KEY = ''
APP_SECRET = ''
THERMOSTAT_ID = ""
def power_state(device_id, state):
print('device_id: {} state: {}'.format(device_id, state))
return True, state
def target_temperature(device_id, temperature):
print('device_id: {} set temperature: {}'.format(device_id, temperature))
return True, temperature
def set_thermostate_mode(device_id, thermostat_mode):
print('device_id: {} set thermostat mode: {}'.format(device_id, thermostat_mode))
return True, thermostat_mode
def mode_value(device_id, mode_value):
print(device_id, mode_value)
return True, mode_value
async def events():
while True:
client.event_handler.raise_event(THERMOSTAT_ID, SinricProConstants.SET_THERMOSTAT_MODE, data= { SinricProConstants.MODE : 'COOL'}) #*** this doesn't work for me
# client.event_handler.raise_event(THERMOSTAT_ID, SinricProConstants.SET_POWER_STATE, data= {SinricProConstants.STATE: SinricProConstants.POWER_STATE_OFF})
#client.event_handler.raise_event(THERMOSTAT_ID, SinricProConstants.CURRENT_TEMPERATURE, data={'humidity': 75.3, 'temperature': 11}) # *** this does works for me
# Server will trottle / block IPs sending events too often.
await sleep(60)
callbacks = {
SinricProConstants.SET_POWER_STATE: power_state,
SinricProConstants.TARGET_TEMPERATURE: target_temperature,
SinricProConstants.SET_THERMOSTAT_MODE: set_thermostate_mode
}
if __name__ == '__main__':
loop = asyncio.get_event_loop()
client = SinricPro(APP_KEY, [THERMOSTAT_ID], callbacks, event_callbacks=events,
enable_log=True, restore_states=False, secret_key=APP_SECRET)
loop.run_until_complete(client.connect())
I think I know why.
elif response_cmd == SinricProConstants.SET_THERMOSTAT_MODE:
if self.bucket.add_dropp(): << -- should be add_drop():
Sometime back we fixed this but never released it. So it was working on my local but not in production.
Please install the new version: 2.7.5 https://pypi.org/project/sinricpro/2.7.5/
Thank you for the change, I've update the package and it works - partially. Still using the example code you sent me, now it does triggers the event but the Mode does not update on the device UI in the SinricPro portal. I have to refresh the page and then it shows the change. But when I change the temperature via python, the UI portal reflects it immediately. Also, the esp8266 doesn't get the Mode change if triggered from python, but if I change the Mode via the portal UI, the esp8266 receives it properly.
Also, how can I adjust the target-temperature?
I tried the following:
client.event_handler.raise_event(THERMOSTAT_ID, SinricProConstants.ADJUST_TARGET_TEMPERATURE, data={'temperature': 33})
I get an error: adjustTargetTemperature not found!
client.event_handler.raise_event(THERMOSTAT_ID, SinricProConstants.TARGET_TEMPERATURE, data={'temperature': 33})
I get an error: targetTemperature not found!
EDIT:
When I change the target-temperature from the portal then python callback shows "payload": {"action": "targetTemperature" ...
client.event_handler.raise_event(THERMOSTAT_ID, SinricProConstants.TARGET_TEMPERATURE, data= { SinricProConstants.TEMPERATURE : 10})
This has been fixed now. Please use https://pypi.org/project/sinricpro/2.7.7/
Portal not automatically refreshing issue: I noticed this too. Will release a fix tomorrow.
" the esp8266 doesn't get the Mode change if triggered from python, but if I change the Mode via the portal UI, the esp8266 receives it properly."
Yes. this is the intended behavior. Python and ESP8266 are clients. They send commands to the server, the server processes them. You can't send a command from client to client
Are you trying to control the ESP8266? If Yes, then you should use the API to send a command to ESP8266 https://help.sinric.pro/pages/tutorials/api-guide
The fix works. Yes now I understand, I will likely need to use the API. Unrelated to python, can I use the API from ESP8266 instead of having it as an official client? Being a SinricPro client on the ES8266 is blocking the device from doing api calls to another api/service. I think you replied to my email about it. It might be lack of memory.
If I can use the API from ESP8266, is there a way I can have a sudo client that will pretend the device is online just to be able to use the API?
You can call the SinricPro API to send a command to SinricPro device (same like portal or app) however it will not pretend to be a device in the system.
esp-8266-32-sdk and python sdk are used to represent devices in the system. They connect and receive a commands and send a response or an event.
If you can share more details about the project, we can try to help you to find the best solution.
I would make a feature suggestion of having a device "always online", to be able to use it with the API only, without a running client.
Thank you for offering to review my project. I use the esp8266 to control a servo motor based on temperature DS18B20. I setup the esp as a "thermostat" device type on the SinricPro platform, it works great. The main reason I chose SinricPro was the Google Home integration, and it has been working great. Recently I found an API to interface with my wireless temperature sensors, they are connected to the main thermostat - Wyze thermostat and room sensors). I wanted to use them instead of the DS18B20 because they are already where I need them and it would simplify the board by having one less cable coming out of it. The challenge now is that I can't seem to call the Wyze API from the esp while having SinricPro.handle() running, it crashes and restarts the ESP, maybe memory issue. I haven't checked if it is working on the 32 but I'm already invested with the 8266. If there was a way to keep the device online without actually having a client than I would use API calls on the ESP for both SinricPro and Wyze. I guess now I'll have the python do those Wyze API calls and send it to the ESP SinricPro client via the SinricPro API. I do wonder if micropython would work.
Any recommendations?
Using the API, which event do I use to set the temperature (current temperature, not target temperature)
With python as a client this works
client.event_handler.raise_event(THERMOSTAT_ID, SinricProConstants.CURRENT_TEMPERATURE, data={'humidity': 75.3, 'temperature': 11})
In the ESP, this works:
myThermostat.sendTemperatureEvent (temperatureC,humidity);
In the API this worked to set the TargetTemprature (not current temperature)
...&action=targetTemperature&value={"temperature": "25"}
For temperature (current temperature) I tried different things for the API and it wouldn't work.
...&action=temperature&value={"temperature": "25"}
...&action=setTemperature&value={"temperature": "25"}
...&action=currentTemperature&value={"temperature": "25"}
...&action=setCurrentTemperature&value={"temperature": "25"}
When I attempted these, I get these messages in the portal
EDIT:
By getting all devices using the API, I see the list of actions per device
'actions': ['setPowerState', 'targetTemperature', 'setThermostatMode']
There is no way to set the current temperature via API? only via clients?
I see in https://github.com/sinricpro/sample_messages/tree/master
What is an action?
Act of doing something using voice, app or website will generate an action message in the system. Eg: Alexa, turn on the tv will generate setPowerState action.
What is an event ?
Changing the device state physically should raise an event to let the server know about the changes the user made. Eg: pushing a button to turn on the device should send "setPowerState" event to let the server know.
Events cannot be triggered from the API?
Thanks for taking the time to explain what you are trying to achieve.
My suggestions are
Simply put ESP8266 cannot handle HTTPS and HTTP connections plus whatever you have. If you have added #define SINRICPRO_NOSSL
on top of the sketch and still fail, you could try investing more by enabling logs to make sure it's related to memory or something else.
To enable ESP8266 logs, in Arduino IDE: Tools -> Debug Serial Port -> Serial Tools -> Debug Level -> SSL + HTTP_CLIENT
Use the Python SDK, call wyze via wyze-sdk and then call client.event_handler.raise_event(THERMOSTAT_ID, SinricProConstants.CURRENT_TEMPERATURE, data={'humidity': 75.3, 'temperature': 24})
Create a separate temperature sensor device type, call Wyze API, and send the event
You can't set the current temperature using the API. Current temperature is something that senses and notifies to the server via events from client sdks
GET https://api.sinric.pro/api/v1/devices/
eg:
createdAt = unix time in seconds value = URL encoded.
BTW: like the persistence
Thank you again for the quick replies and all the great suggestions and information. I like #4 and I understand it might stop working in the future but for now I already want to make it work and then continue and improve it.
Use an ESP32.
I will try just to see if it works on it.
If you have added #define SINRICPRO_NOSSL on top of the sketch and still fail
I did try it and it didn't help.
To enable ESP8266 logs, in Arduino IDE:
Tools -> Debug Serial Port -> Serial
Tools -> Debug Level -> SSL + HTTP_CLIENT
I tried it before and the output didn't help me understand what is happening but I can paste it here, maybe you can help me "decode" it.
Use the Python SDK, call wyze via wyze-sdk and then call client.event_handler.raise_event(THERMOSTAT_ID, SinricProConstants.CURRENT_TEMPERATURE, data={'humidity': 75.3, 'temperature': 24})
But this means the same device_id would be used both in the python SDK client and in the ESP8266 cleint, When I did it before I think I noticed it makes the device offline, which make sense as it confuses the server who is the real client(?)
You can't set the current temperature using the API. Current temperature is something that senses and notifies to the server via events from client sdks
Yes I understand, it makes perfect sense, however it wouldn't hurt anything if the API would have that capability, even though I admit it is an edge scenario.
createdAt = unix time in seconds
What is this used for? what happens if I put a random value in it that doesn't represent that "now"?
I tried
GET https://api.sinric.pro/api/v1/devices/<YOUR_DEVICE_ID>/action?clientId=portal&type=event&action=currentTemperature&createdAt=<TIME_STAMP>&value=
and it does change the temperature in the portal but I realise it won't change the temp in the esp client. I see there is no event for that obviusly because the esp is supposed to be the one that send the temperature form the physical sensor.
Do you have an advise how I can archive it? Meaning to send the temp to the esp.
Hello,
I think you can skip the timestamp, it’s filled by the server. It’s used to avoid replay attacks. Server will reject the response if it’s older than 4 mins
If you change “event” to “request” it should send the temperature to the esp
GET https://api.sinric.pro/api/v1/devices/
There are sample messages here for events and requests
If you change “event” to “request” it should send the temperature to the esp
GET https://api.sinric.pro/api/v1/devices/<YOUR_DEVICE_ID>/action?clientId=portal&type=request …..
clientId=portal&type=request&action=currentTemperature&createdAt=1550493108338&value=%7B%22temperature%22 Sorry for the silly question, which event would it fire on the ESP?
Please try
clientId=portal&type=request&action=targetTemperature&createdAt=1724721376&value=%7B%22temperature%22
Your createdAt (1550493108338) seems to be in milliseconds. please change it to seconds.
this would trigger the onTargetTemperature
that is for targetTemperature, but I'm looking for a way to send the esp the currentTemperature
I ended up doing the worlds ugliest hack... To send the currentTemp from python to the ESP using the SinricPro API, I piggyback on the TargetTemp to use the onTargetTemperature event on the ESP. TargetTemp allows long float value like 21.53456, so I've added the currentTemp value at the end of the actual TargetTemp. Once received at the esp I check if there is anything after the 1st fracture digit, if no it just changes the TargetTemp, if yes it needs to handle it. It extract the embedded temp value from the TargetTemp and sends the event sendTemperatureEvent i.e. when TargetTemp = 21.53456 then CurrentTemp = 34.56 and TargetTemp = 21.5 Even though the portal set-point increment is 1 degree, Google Home increment are 0.5.
This issue can be closed. Thank you again for all the help and tips.
Indeed.
Should consider moving to ESP32 in the future (any project)
I am able to set thermostat temperature according to the example: https://github.com/sinricpro/python-sdk/blob/master/examples/temperature_sensor.py But I am not able to set thermostat mode. I tried the following:
But I'm getting an error:
'LeakyBucket' object has no attribute 'add_dropp'
. Looks like anytime I tried SET_THERMOSTAT_MODE it gives me the same error.But when I try SET_MODE:
I don't get error but Mode was not changed, instead the portal shows a message that my device is online every time I trigger the event SET_MODE.
Also, seems like Thermostat modes (COOL, HEAT, AUTO, OFF) do not exists in the SinricProConstants (https://github.com/sinricpro/python-sdk/blob/master/sinric/_sinricpro_constants.py)
Maybe separate issue: I'm able to set power state on and off, but in addition it will also show a message that my device is online every time I trigger it.
When I try to use SinricProConstants.POWER_STATE (instead of STATE), which is more intuitive I think, it doesn't work.