-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathtado-assistant.sh
executable file
·231 lines (193 loc) · 9.56 KB
/
tado-assistant.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#!/bin/bash
# Source the environment variables if the file exists
[ -f /etc/tado-assistant.env ] && source /etc/tado-assistant.env
# Create log directory if it doesn't exist
LOG_DIR=$(dirname "$LOG_FILE")
mkdir -p "$LOG_DIR"
declare -A OPEN_WINDOW_ACTIVATION_TIMES TOKENS EXPIRY_TIMES HOME_IDS
LAST_MESSAGE="" # Used to prevent duplicate messages
# Reset the log file if it's older than 10 days
reset_log_if_needed() {
if [ ! -f "$LOG_FILE" ]; then
touch "$LOG_FILE"
fi
local max_age_days=10 # Max age in days (e.g., 10 days)
local current_time
local last_modified
local age_days
local timestamp
local backup_log
current_time=$(date +%s)
last_modified=$(date -r "$LOG_FILE" +%s)
age_days=$(( (current_time - last_modified) / 86400 ))
if [ "$age_days" -ge "$max_age_days" ]; then
timestamp=$(date '+%Y%m%d%H%M%S')
backup_log="${LOG_FILE}.${timestamp}"
mv "$LOG_FILE" "$backup_log"
touch "$LOG_FILE"
echo "🔄 Log reset: $backup_log"
fi
}
# Error handling for curl
handle_curl_error() {
if [ $? -ne 0 ]; then
log_message "Curl command failed. Retrying in 60 seconds."
sleep 60
return 1
fi
return 0
}
# Login function
login() {
local account_index=$1
local username_var=$2
local password_var=$3
local username=${!username_var}
local password=${!password_var}
local response expires_in token home_data home_id
response=$(curl -s -X POST "https://auth.tado.com/oauth/token" \
-d 'client_id=public-api-preview' \
-d 'client_secret=4HJGRffVR8xb3XdEUQpjgZ1VplJi6Xgw' \
-d 'grant_type=password' \
-d 'scope=home.user' \
--data-urlencode 'username='"$username" \
--data-urlencode 'password='"$password")
handle_curl_error
token=$(echo "$response" | jq -r '.access_token')
if [ -z "$token" ] || [ "$token" == "null" ]; then
log_message "❌ Login error for account $account_index: Please check the username and password. Then restart the container or service."
exit 1
fi
TOKENS[$account_index]=$token
expires_in=$(echo "$response" | jq -r '.expires_in')
EXPIRY_TIMES[$account_index]=$(($(date +%s) + expires_in - 60))
home_data=$(curl -s -X GET "https://my.tado.com/api/v2/me" -H "Authorization: Bearer ${TOKENS[$account_index]}")
handle_curl_error
home_id=$(echo "$home_data" | jq -r '.homes[0].id')
if [ -z "$home_id" ]; then
log_message "⚠️ Error fetching home ID for account $account_index!"
exit 1
fi
HOME_IDS[$account_index]=$home_id
}
log_message() {
local message="$1"
reset_log_if_needed
if [ "$ENABLE_LOG" = true ] && [ "$LAST_MESSAGE" != "$message" ]; then
echo "$(date '+%d-%m-%Y %H:%M:%S') # $message" >> "$LOG_FILE"
LAST_MESSAGE="$message"
fi
echo "$(date '+%d-%m-%Y %H:%M:%S') # $message"
}
homeState() {
local home_state mobile_devices devices_home devices_str zones zone_id zone_name home_id current_time account_index
local open_window_detection_supported open_window_detection_enabled open_window_detected
account_index=$1
home_id=${HOME_IDS[$account_index]}
current_time=$(date +%s)
if [ -n "${EXPIRY_TIMES[$account_index]}" ] && [ "$current_time" -ge "${EXPIRY_TIMES[$account_index]}" ]; then
login "$account_index" "TADO_USERNAME_$account_index" "TADO_PASSWORD_$account_index"
fi
home_state=$(curl -s -X GET "https://my.tado.com/api/v2/homes/$home_id/state" -H "Authorization: Bearer ${TOKENS[$account_index]}" | jq -r '.presence')
handle_curl_error
mobile_devices=$(curl -s -X GET "https://my.tado.com/api/v2/homes/$home_id/mobileDevices" -H "Authorization: Bearer ${TOKENS[$account_index]}")
handle_curl_error
mapfile -t devices_home < <(echo "$mobile_devices" | jq -r '.[] | select(.settings.geoTrackingEnabled == true and .location.atHome == true) | .name')
handle_curl_error
if [ "$ENABLE_GEOFENCING" == true ]; then
log_message "🏠 Account $account_index: Geofencing enabled."
local devices_str
if [ ${#devices_home[@]} -gt 0 ] && [ "$home_state" == "HOME" ]; then
devices_str=$(IFS=,; echo "${devices_home[*]}")
log_message "🏠 Account $account_index: Home is in HOME Mode, the devices $devices_str are at home."
elif [ ${#devices_home[@]} -eq 0 ] && [ "$home_state" == "AWAY" ]; then
log_message "🚶 Account $account_index: Home is in AWAY Mode and there are no devices at home."
elif [ ${#devices_home[@]} -eq 0 ] && [ "$home_state" == "HOME" ]; then
log_message "🏠 Account $account_index: Home is in HOME Mode but there are no devices at home."
curl -s -X PUT "https://my.tado.com/api/v2/homes/$home_id/presenceLock" \
-H "Authorization: Bearer ${TOKENS[$account_index]}" \
-H "Content-Type: application/json" \
-d '{"homePresence": "AWAY"}'
handle_curl_error
log_message "Done! Activated AWAY mode for account $account_index."
elif [ ${#devices_home[@]} -gt 0 ] && [ "$home_state" == "AWAY" ]; then
devices_str=$(IFS=,; echo "${devices_home[*]}")
log_message "🚶 Account $account_index: Home is in AWAY Mode but the devices $devices_str are at home."
curl -s -X PUT "https://my.tado.com/api/v2/homes/$home_id/presenceLock" \
-H "Authorization: Bearer ${TOKENS[$account_index]}" \
-H "Content-Type: application/json" \
-d '{"homePresence": "HOME"}'
handle_curl_error
log_message "Done! Activated HOME mode for account $account_index."
fi
else
log_message "🏠 Account $account_index: Geofencing disabled."
fi
# Fetch zones for the home
zones=$(curl -s -X GET "https://my.tado.com/api/v2/homes/$home_id/zones" -H "Authorization: Bearer ${TOKENS[$account_index]}")
handle_curl_error
echo "$zones" | jq -c '.[]' | while read -r zone; do
zone_id=$(echo "$zone" | jq -r '.id')
zone_name=$(echo "$zone" | jq -r '.name')
open_window_detection_supported=$(echo "$zone" | jq -r '.openWindowDetection.supported')
if [ "$open_window_detection_supported" = false ]; then
continue
fi
open_window_detection_enabled=$(echo "$zone" | jq -r '.openWindowDetection.enabled')
if [ "$open_window_detection_enabled" = false ]; then
continue
fi
open_window_detected=$(curl -s -X GET "https://my.tado.com/api/v2/homes/$home_id/zones/$zone_id/state" -H "Authorization: Bearer ${TOKENS[$account_index]}" | jq -r '.openWindowDetected')
handle_curl_error
if [ "$open_window_detected" == "true" ]; then
current_time=$(date +%s)
# Check if the open window mode was recently activated and MAX_OPEN_WINDOW_DURATION is set
if [ -n "${OPEN_WINDOW_ACTIVATION_TIMES[$zone_id]}" ] && [ -n "$MAX_OPEN_WINDOW_DURATION" ]; then
local activation_time=${OPEN_WINDOW_ACTIVATION_TIMES[$zone_id]}
local time_diff=$((current_time - activation_time))
if [ "$time_diff" -gt "$MAX_OPEN_WINDOW_DURATION" ]; then
log_message "❄️ Account $account_index: $zone_name: Open window detected for more than $MAX_OPEN_WINDOW_DURATION seconds. Cancelling open window mode."
# Cancel open window mode for the zone
curl -s -X DELETE "https://my.tado.com/api/v2/homes/$home_id/zones/$zone_id/state/openWindow" \
-H "Authorization: Bearer ${TOKENS[$account_index]}"
handle_curl_error
log_message "✅ Account $account_index: Cancelled open window mode for $zone_name."
unset "OPEN_WINDOW_ACTIVATION_TIMES[$zone_id]"
continue
fi
fi
log_message "❄️ Account $account_index: $zone_name: Open window detected, activating OpenWindow mode."
# Set open window mode for the zone
curl -s -X POST "https://my.tado.com/api/v2/homes/$home_id/zones/$zone_id/state/openWindow/activate" \
-H "Authorization: Bearer ${TOKENS[$account_index]}"
handle_curl_error
log_message "🌬️ Account $account_index: Activating open window mode for $zone_name."
# Record the activation time
OPEN_WINDOW_ACTIVATION_TIMES[$zone_id]=$current_time
fi
done
log_message "⏳ Account $account_index: Waiting for a change in devices location or for an open window.."
}
# Main execution loop
for (( i=1; i<=NUM_ACCOUNTS; i++ )); do
USERNAME_VAR="TADO_USERNAME_$i"
PASSWORD_VAR="TADO_PASSWORD_$i"
CHECKING_INTERVAL_VAR="CHECKING_INTERVAL_$i"
MAX_OPEN_WINDOW_DURATION_VAR="MAX_OPEN_WINDOW_DURATION_$i"
ENABLE_GEOFENCING_VAR="ENABLE_GEOFENCING_$i"
ENABLE_LOG_VAR="ENABLE_LOG_$i"
LOG_FILE_VAR="LOG_FILE_$i"
# Fetch dynamic variables
CHECKING_INTERVAL=${!CHECKING_INTERVAL_VAR:-15}
MAX_OPEN_WINDOW_DURATION=${!MAX_OPEN_WINDOW_DURATION_VAR:-}
ENABLE_GEOFENCING=${!ENABLE_GEOFENCING_VAR:-false}
ENABLE_LOG=${!ENABLE_LOG_VAR:-false}
LOG_FILE=${!LOG_FILE_VAR:-'/var/log/tado-assistant.log'}
# Login and get the home ID
login "$i" "$USERNAME_VAR" "$PASSWORD_VAR"
# Loop to monitor home state
while true; do
homeState "$i"
sleep "$CHECKING_INTERVAL"
done
done