patrickligardes commited on
Commit
6621159
·
verified ·
1 Parent(s): f4718ad

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +205 -0
app.py ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import requests
3
+ import time
4
+ from datetime import datetime
5
+ import json
6
+ import threading
7
+ import queue
8
+
9
+ class EzvizTuyaAutomation:
10
+ def __init__(self):
11
+ self.ezviz_base_url = "https://open.ezviz.com/api"
12
+ self.tuya_base_url = "https://openapi.tuyaus.com"
13
+ self.credentials = {
14
+ 'ezviz_app_key': '',
15
+ 'ezviz_app_secret': '',
16
+ 'tuya_client_id': '',
17
+ 'tuya_secret': ''
18
+ }
19
+ self.ezviz_access_token = None
20
+ self.tuya_access_token = None
21
+ self.selected_camera = None
22
+ self.selected_light = None
23
+ self.is_running = False
24
+ self.status_queue = queue.Queue()
25
+
26
+ def get_ezviz_devices(self):
27
+ """Get list of EZVIZ cameras"""
28
+ if not self.ezviz_access_token:
29
+ return []
30
+
31
+ url = f"{self.ezviz_base_url}/devices"
32
+ headers = {"Authorization": f"Bearer {self.ezviz_access_token}"}
33
+ response = requests.get(url, headers=headers)
34
+ if response.status_code == 200:
35
+ devices = response.json().get("devices", [])
36
+ return [{"name": dev["name"], "id": dev["deviceSerial"]} for dev in devices]
37
+ return []
38
+
39
+ def get_tuya_devices(self):
40
+ """Get list of Tuya devices"""
41
+ if not self.tuya_access_token:
42
+ return []
43
+
44
+ url = f"{self.tuya_base_url}/v1.0/devices"
45
+ headers = {
46
+ "Authorization": f"Bearer {self.tuya_access_token}",
47
+ "Content-Type": "application/json"
48
+ }
49
+ response = requests.get(url, headers=headers)
50
+ if response.status_code == 200:
51
+ devices = response.json().get("devices", [])
52
+ return [{"name": dev["name"], "id": dev["id"]} for dev in devices]
53
+ return []
54
+
55
+ def check_motion(self):
56
+ """Check for motion events from selected EZVIZ camera"""
57
+ if not self.ezviz_access_token or not self.selected_camera:
58
+ return False
59
+
60
+ url = f"{self.ezviz_base_url}/devices/{self.selected_camera}/events"
61
+ headers = {"Authorization": f"Bearer {self.ezviz_access_token}"}
62
+ response = requests.get(url, headers=headers)
63
+ if response.status_code == 200:
64
+ events = response.json().get("events", [])
65
+ current_time = time.time()
66
+ for event in events:
67
+ if (event.get("type") == "motion" and
68
+ current_time - event.get("timestamp", 0) <= 30):
69
+ return True
70
+ return False
71
+
72
+ def control_light(self, turn_on=True):
73
+ """Control selected Tuya device"""
74
+ if not self.tuya_access_token or not self.selected_light:
75
+ return False
76
+
77
+ url = f"{self.tuya_base_url}/v1.0/devices/{self.selected_light}/commands"
78
+ headers = {
79
+ "Authorization": f"Bearer {self.tuya_access_token}",
80
+ "Content-Type": "application/json"
81
+ }
82
+ command = {
83
+ "commands": [
84
+ {
85
+ "code": "switch_led",
86
+ "value": turn_on
87
+ }
88
+ ]
89
+ }
90
+ response = requests.post(url, headers=headers, json=command)
91
+ return response.status_code == 200
92
+
93
+ def automation_loop(self):
94
+ """Main automation loop"""
95
+ last_motion_time = 0
96
+ while self.is_running:
97
+ try:
98
+ if self.check_motion():
99
+ current_time = time.time()
100
+ if current_time - last_motion_time > 30:
101
+ message = f"Motion detected at {datetime.now()}"
102
+ self.status_queue.put(message)
103
+ if self.control_light(True):
104
+ self.status_queue.put("Light turned on successfully")
105
+ last_motion_time = current_time
106
+ else:
107
+ self.status_queue.put("Failed to control light")
108
+ time.sleep(5)
109
+ except Exception as e:
110
+ self.status_queue.put(f"Error: {str(e)}")
111
+ time.sleep(30)
112
+
113
+ def create_ui():
114
+ automation = EzvizTuyaAutomation()
115
+
116
+ def update_credentials(ezviz_key, ezviz_secret, tuya_id, tuya_secret):
117
+ automation.credentials.update({
118
+ 'ezviz_app_key': ezviz_key,
119
+ 'ezviz_app_secret': ezviz_secret,
120
+ 'tuya_client_id': tuya_id,
121
+ 'tuya_secret': tuya_secret
122
+ })
123
+ return "Credentials updated"
124
+
125
+ def get_devices():
126
+ # Get and refresh device lists
127
+ ezviz_devices = automation.get_ezviz_devices()
128
+ tuya_devices = automation.get_tuya_devices()
129
+
130
+ ezviz_choices = [f"{dev['name']} ({dev['id']})" for dev in ezviz_devices]
131
+ tuya_choices = [f"{dev['name']} ({dev['id']})" for dev in tuya_devices]
132
+
133
+ return gr.Dropdown.update(choices=ezviz_choices), gr.Dropdown.update(choices=tuya_choices)
134
+
135
+ def start_automation(camera_choice, light_choice):
136
+ if not camera_choice or not light_choice:
137
+ return "Please select both a camera and a light device"
138
+
139
+ automation.selected_camera = camera_choice.split('(')[1].rstrip(')')
140
+ automation.selected_light = light_choice.split('(')[1].rstrip(')')
141
+ automation.is_running = True
142
+
143
+ # Start automation in a separate thread
144
+ thread = threading.Thread(target=automation.automation_loop)
145
+ thread.daemon = True
146
+ thread.start()
147
+
148
+ return "Automation started"
149
+
150
+ def stop_automation():
151
+ automation.is_running = False
152
+ return "Automation stopped"
153
+
154
+ def get_status():
155
+ status_messages = []
156
+ while not automation.status_queue.empty():
157
+ status_messages.append(automation.status_queue.get())
158
+ return "\n".join(status_messages) if status_messages else "No new updates"
159
+
160
+ with gr.Blocks(title="EZVIZ-Tuya Automation") as app:
161
+ with gr.Row():
162
+ with gr.Column():
163
+ gr.Markdown("### API Credentials")
164
+ ezviz_key = gr.Textbox(label="EZVIZ App Key")
165
+ ezviz_secret = gr.Textbox(label="EZVIZ App Secret", type="password")
166
+ tuya_id = gr.Textbox(label="Tuya Client ID")
167
+ tuya_secret = gr.Textbox(label="Tuya Secret", type="password")
168
+ save_btn = gr.Button("Save Credentials")
169
+
170
+ with gr.Row():
171
+ refresh_btn = gr.Button("Refresh Device Lists")
172
+ camera_dropdown = gr.Dropdown(label="Select EZVIZ Camera", choices=[])
173
+ light_dropdown = gr.Dropdown(label="Select Tuya Light", choices=[])
174
+
175
+ with gr.Row():
176
+ start_btn = gr.Button("Start Automation")
177
+ stop_btn = gr.Button("Stop Automation")
178
+
179
+ status_text = gr.Textbox(label="Status", interactive=False)
180
+
181
+ # Update status every 5 seconds
182
+ status_text.change(get_status, None, status_text, every=5)
183
+
184
+ # Button click handlers
185
+ save_btn.click(update_credentials,
186
+ inputs=[ezviz_key, ezviz_secret, tuya_id, tuya_secret],
187
+ outputs=gr.Textbox(label="Status"))
188
+
189
+ refresh_btn.click(get_devices,
190
+ None,
191
+ outputs=[camera_dropdown, light_dropdown])
192
+
193
+ start_btn.click(start_automation,
194
+ inputs=[camera_dropdown, light_dropdown],
195
+ outputs=gr.Textbox(label="Status"))
196
+
197
+ stop_btn.click(stop_automation,
198
+ None,
199
+ outputs=gr.Textbox(label="Status"))
200
+
201
+ return app
202
+
203
+ if __name__ == "__main__":
204
+ app = create_ui()
205
+ app.launch()