Привет! Недавно я сменил Asus RT-AC66U на точки доступа Ubiquiti AC PRO и значительно улучшил стабильность и качество своей WiFi-сети. Однако на Asus (прошивка Merlin) у меня работал скрипт, который определял, есть ли устройство в сети WiFi (проверяя конкретный MAC-адрес), и в зависимости от его присутствия вызывал команду в мою систему умного дома (Vera), чтобы сообщить, что устройство больше не в сети. Таким образом я мог определять, находится ли кто-то дома. У меня был скрипт автозапуска и сам скрипт, который выполнял эту задачу. Пример скрипта приведён ниже.
Пару вопросов:
Могу ли я запускать такой скрипт на Unifi AC Pro? Есть ли способ не запускать скрипт на каждой точке доступа, а выполнять его через контроллер Unifi или с EdgeRouter?
#!/bin/sh
# Автор: reardencode <freedom@reardencode.com>
# Этот скрипт устанавливает состояния мультипереключателей в зависимости от статуса серверов
# в вашей сети, а также присутствия устройств по MAC-адресам.
# Вы можете мониторить практически любые комбинации хостов и MAC-адресов, главное —
# назначить их уникальным мультипереключателям.
# Инструкция:
# * Настройте переменные в начале скрипта под свою конфигурацию
# * Поместите скрипт в /jffs/scripts или /usr/bin или куда угодно на вашем роутере
# * Сделайте его исполняемым: chmod +x /path/to/this/script
# * Добавьте '/path/to/this/script&' в /etc/rc.local (через CLI или GUI)
# * Запустите скрипт '/path/to/this/script&' из CLI или перезагрузите роутер
iw_devices="wlan0 wlan1"
macs="<mac1>,<device1>,<switch1> <mac2>,<device2>,<switch2>"
hosts="<host1>,<device1>,<switch1> <host2>,<device2>,<switch2>"
vera_ip=<ip>
# Как часто опрашивать устройства/хосты
poll_seconds=1
# Как долго устройство может быть отключено перед переключением переключателя в 0
timeout_seconds=60
# Интервал обновления состояний переключателей при том же состоянии устройства
refresh_seconds=300
base_query="id=lu_action&serviceId=urn:dcineco-com:serviceId:MSwitch1"
base_url="http://$vera_ip:3480/data_request?$base_query"
get_var_name() {
local device_switch=${3#*,}
echo ${1}_${2}_${device_switch%,*}_${device_switch#*,}
}
set_state() {
local host_or_mac=$1
local item=$2
local new_state=$3
local old_state=$4
local name=${item%%,*}
local device_switch=${item#*,}
local device=${device_switch%,*}
local switch=${device_switch#*,}
local params="DeviceNum=$device&action=SetStatus$switch&newStatus$ switch=$new_state"
if [ $new_state -ne $old_state ]; then
echo "Устанавливаю $device.$switch ($name) в состояние $new_state"
if wget -T 1 -O - "$base_url&$params" > /dev/null 2>&1; then
eval $(get_var_name $host_or_mac state $item)=$new_state
fi
fi
}
poll_mac() {
for iw_device in $iw_devices; do
if iw dev $iw_device station get $1 > /dev/null 2>&1; then
return 0
fi
done
return 1
}
poll_host() {
ping -w 1 -c 1 $1 > /dev/null 2>&1
return $?
}
poll_states() {
local host_or_mac=$1
eval local items=\$${host_or_mac}s
for item in $items; do
eval local state=\$$(get_var_name $host_or_mac state $item)
if eval poll_$host_or_mac ${item%%,*}; then
set_state $host_or_mac $item 1 $state
eval $(get_var_name $host_or_mac count $item)=$timeout_seconds
else
eval local count=\$$(get_var_name $host_or_mac count $item)
if [ $count -le 0 ]; then
set_state $host_or_mac $item 0 $state
else
eval $(get_var_name $host_or_mac count $item)=$((count-poll_seconds))
fi
fi
done
}
init_counts() {
local host_or_mac=$1
eval local items=\$${host_or_mac}s
for item in $items; do
eval $(get_var_name $host_or_mac count $item)=$timeout_seconds
done
}
clear_states() {
local host_or_mac=$1
eval local items=\$${host_or_mac}s
for item in $items; do
eval $(get_var_name $host_or_mac state $item)=-1
done
}
main() {
local refresh=0
init_counts host
init_counts mac
while true; do
if [ $refresh -le 0 ]; then
clear_states host
clear_states mac
refresh=$refresh_seconds
fi
poll_states host
poll_states mac
sleep $poll_seconds
refresh=$((refresh-poll_seconds))
done
}
main
Пару вопросов:
Могу ли я запускать такой скрипт на Unifi AC Pro? Есть ли способ не запускать скрипт на каждой точке доступа, а выполнять его через контроллер Unifi или с EdgeRouter?
#!/bin/sh
# Автор: reardencode <freedom@reardencode.com>
# Этот скрипт устанавливает состояния мультипереключателей в зависимости от статуса серверов
# в вашей сети, а также присутствия устройств по MAC-адресам.
# Вы можете мониторить практически любые комбинации хостов и MAC-адресов, главное —
# назначить их уникальным мультипереключателям.
# Инструкция:
# * Настройте переменные в начале скрипта под свою конфигурацию
# * Поместите скрипт в /jffs/scripts или /usr/bin или куда угодно на вашем роутере
# * Сделайте его исполняемым: chmod +x /path/to/this/script
# * Добавьте '/path/to/this/script&' в /etc/rc.local (через CLI или GUI)
# * Запустите скрипт '/path/to/this/script&' из CLI или перезагрузите роутер
iw_devices="wlan0 wlan1"
macs="<mac1>,<device1>,<switch1> <mac2>,<device2>,<switch2>"
hosts="<host1>,<device1>,<switch1> <host2>,<device2>,<switch2>"
vera_ip=<ip>
# Как часто опрашивать устройства/хосты
poll_seconds=1
# Как долго устройство может быть отключено перед переключением переключателя в 0
timeout_seconds=60
# Интервал обновления состояний переключателей при том же состоянии устройства
refresh_seconds=300
base_query="id=lu_action&serviceId=urn:dcineco-com:serviceId:MSwitch1"
base_url="http://$vera_ip:3480/data_request?$base_query"
get_var_name() {
local device_switch=${3#*,}
echo ${1}_${2}_${device_switch%,*}_${device_switch#*,}
}
set_state() {
local host_or_mac=$1
local item=$2
local new_state=$3
local old_state=$4
local name=${item%%,*}
local device_switch=${item#*,}
local device=${device_switch%,*}
local switch=${device_switch#*,}
local params="DeviceNum=$device&action=SetStatus$switch&newStatus$
if [ $new_state -ne $old_state ]; then
echo "Устанавливаю $device.$switch ($name) в состояние $new_state"
if wget -T 1 -O - "$base_url&$params" > /dev/null 2>&1; then
eval $(get_var_name $host_or_mac state $item)=$new_state
fi
fi
}
poll_mac() {
for iw_device in $iw_devices; do
if iw dev $iw_device station get $1 > /dev/null 2>&1; then
return 0
fi
done
return 1
}
poll_host() {
ping -w 1 -c 1 $1 > /dev/null 2>&1
return $?
}
poll_states() {
local host_or_mac=$1
eval local items=\$${host_or_mac}s
for item in $items; do
eval local state=\$$(get_var_name $host_or_mac state $item)
if eval poll_$host_or_mac ${item%%,*}; then
set_state $host_or_mac $item 1 $state
eval $(get_var_name $host_or_mac count $item)=$timeout_seconds
else
eval local count=\$$(get_var_name $host_or_mac count $item)
if [ $count -le 0 ]; then
set_state $host_or_mac $item 0 $state
else
eval $(get_var_name $host_or_mac count $item)=$((count-poll_seconds))
fi
fi
done
}
init_counts() {
local host_or_mac=$1
eval local items=\$${host_or_mac}s
for item in $items; do
eval $(get_var_name $host_or_mac count $item)=$timeout_seconds
done
}
clear_states() {
local host_or_mac=$1
eval local items=\$${host_or_mac}s
for item in $items; do
eval $(get_var_name $host_or_mac state $item)=-1
done
}
main() {
local refresh=0
init_counts host
init_counts mac
while true; do
if [ $refresh -le 0 ]; then
clear_states host
clear_states mac
refresh=$refresh_seconds
fi
poll_states host
poll_states mac
sleep $poll_seconds
refresh=$((refresh-poll_seconds))
done
}
main
