Блог Книжки Блогрол

Як я створив віджет з інформацією, чи є електроенергія вдома

Як я створив віджет з інформацією, чи є електроенергія вдома
Зображення згенероване AI Midjourney по запиту «українці сидять в кафе без електрики зі свічками та нервово дивляться в iphone»

Ще до початку війни відкрив для себе Scriptable — iOS-додаток для створення віджетів на православному JavaScript. А так як нам Тім Кук ще й дозволив створювати віджети для домашнього екрана, то треба цим користуватись!

Колись було досить багато ідей (і я створював віджети з кількістю відвідувачів карти тривог, але коли їх стало дуже багато, то перестав гратись і продався Google Analytics), але в новій реальності у нас в країні війна, і поки агресор не розпався на багато інших, то одна з проблем їх існування – періодична відсутність світла вдома. Через те, що графік не сходиться з реальним вимкненням світла, не завжди зрозуміло, чи пора повертатись додому.

В результаті у мене вийшов ось такий віджет:

Далі йдуть технічні моменти, а внизу інструкція, як додати його собі – якщо хтось працює на 66-му поверсі Карнегі Центра, і не знає, чи вже можна їхати на Печерськ, щоб не підійматись сходами.

Оновлено: Як правильно зазначили в твітерах [1, 2], віджет фактично перевіряє, чи доступний ваш роутер в інтернеті. Можуть бути випадки, що електроенергія є, хоча самого інтернету немає – в такому випадку, віджет все ще буде червоним. В мене в таких випадках інтернет зʼявлявся протягом 5-ти хвилин, але можуть бути такі проблеми також.

No-Сode?

Спочатку я думав виводити віджет на заблокованому екрані, і знайшов Any Text, який підтримує інтеграцію з Shortcuts. Їх навіть можна запускати по розкладу, але мінімальна періодичність – день. Якщо я хочу оновлювати кожні 15 хвилин, то потрібно створити 96 автоматизацій, і кожну з них вручну. Інших варіантів я так і не знайшов, тому ідея з ноукодом швидко провалилась.

Шо по пінгу роутера?

Найпростіший спосіб перевірити, чи є інтернет вдома – зробити пінг на IP адресу роутера, а Scriptable (читай ES6) не вміє робити запити по icmp-протоколу. З доступних ресурсів я знайшов API, яке робить пінг, але там досить довго потрібно чекати на результати – мені достатньо хоча б одного результату, а не перевіряти, чи відповідає мій роутер з усіх материків. Тому треба було створити свій мікросервіс!

Підіймати сервер для одного запиту – така собі ідея, і я спочатку подумав про DigitalOcean Functions (а-ля AWS Lambda), але є проблема, що складно обмежувати кількість запитів в разі необхідності, раптом росіяни почнуть навантажувати сервіс своїми запитами, як і зробили з карти тривог.

А потім я згадав пост Антона (і ось зараз помітив, що там якраз і за Scriptable мова була), що в nginx можна писати на lua, і це виглядало ідеальним рішенням! Тому з гівна та палок за пару хвилин я зібрав швиденько ендпоінт, який робить ping заданої IP-адреси та повертає інформацію, чи доступний він.

server {
    # ...
    location /ping/ {
        default_type 'application/json';
        content_by_lua '
            local cjson = require "cjson"

            if ngx.var.arg_ip == nil then
                ngx.say(cjson.encode({status="error", error="Передайте IP через ?ip= параметр. Наприклад, ?ip=127.0.0.1"}));
                return
            end

            local ip = ngx.var.arg_ip;
            local chunks = {ip:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)$")}
            if #chunks == 4 then
              for _,v in pairs(chunks) do
                if tonumber(v) > 255 then ngx.say(cjson.encode({status="error", error="Додайте коректний IP в налаштуваннях"})) return end
              end
            else
              ngx.say(cjson.encode({status="error", error="Додайте коректний IP в налаштуваннях"})); return
            end

            local handle = io.popen("ping -c 1 " .. ngx.var.arg_ip .. " -W 0.5", "r")
            local out = handle:read("*all")
            handle:close()
            if string.find(out, "1 received") then
                ngx.say(cjson.encode({status="ok"}))
            else
                ngx.say(cjson.encode({status="error"}))
            end
        ';
    }
}

І все запрацювало!

Віджет

Віджет виявився найпростішою частиною, і на основі інших прикладів я швиденько зробив віджет, який показує стан та дату оновлення. Сам код віджета в файлі нижче – там один запит, відображення його та часу генерації, і ніякого рокет саєнс!

Що треба ще знати

Вдома повинен бути завжди статичний IP так як з динамічним складно працювати.

Також iOS сама вирішує, коли їй оновити віджет, і робить це по документації в інтервалі 15..60 хвилин, але фактично в мене виходило 15-20 хвилин. Якщо тапнути по віджету – він оновиться з актуальними даними.

Як?

  1. Повинен бути статичний IP. Якщо роутер вимкнути-увімкнути, і IP зміниться – потрібно буде у провайдера замовляти додатково послугу статичного IP. Віджет постійно перевіряє лише одну і ту ж адресу.
  2. Роутер повинен відповідати на ping запити. Якщо повертається помилка при натисканні на кнопку «Надіслати пінг на мій IP», то треба гуглити щось «%router name% Respond to Pings from WAN» та вмикати  на роутері
  3. Потрібно встановити Scriptable, завантажити файл нижче, поділитись ним в Scriptable та замінити IP в першому рядку на потрібний. Раптом що, ось відео, як це робиться.
  4. Створити віджет та додати його на домашній екран.
  5. Всьо!

Що далі?

Взагалі в мене ще була ідея пройтись по закладах та зробити невелику краудсорсинг-карту з закладами та станом вайфаю в реальному часі. Можна також зробити якогось телеграм-бота або надсилати сповіщення при зміні стану світла.

Або можна зробити якусь zapier-інтеграцію для слака, щоб всі бачили, що у вас немає світла, і що можлива якась затримка в для відповідей. Я якось робив таке для сирен, тому повинно бути максимально просто і зробити для світла також.

💌 Підписочка!

Зазвичай я пишу про свої невеликі проєкти, дослідження, про прочитані книжки та все цікаве, що знаходжу для себе.

Без спаму та AI – лише мій крафтовий контент!

Анонси також можна побачити у мене в твітері, блускаї або підписатись на RSS.

© Клименко Вадим
[email protected]
Підписочка
На e-mail або RSS
Соцмережі
Твітер / Блускай / Фейсбук
Цікавеньке
Блогрол
Створено під час повітряних бледін у  Fill 3 Києві