Lumen Taba на страже продуктивности: пишем собственное приложение для умной лампочки

в 8:31, , рубрики: DIY, Lumen, node.js, osx, swift, work productivity, Блог компании Даджет, гаджеты, Лайфхаки для гиков, Программирование, умный дом

imageВсем привет, я давно интересуюсь «умным» домом, а в частности программированием каких-нибудь подручных девайсов. В прошлый раз я поставил на свой роутер OpenWrt и через телефон с помощью GPIO открывал входную дверь (пока что макет). На этот раз дело будет связанно с продуктивностью, а не безопасностью.

Многие уже слышали про «умные» лампочки, которые умеют менять цвета и даже мигать под музыку. И вот не так давно я получил одну такую в свои руки. Это LuMini. Кому из нас, программистов, интересен просто «умный» девайс, для которого мы не можем сделать свое приложений, а идей то много.

Оказывается, LuMini именно для нас. Открыв родное приложение для iOS, я сразу понял, что к лампочке я доступ получу. Лампочка подключалась магическим способом, и после ее подключения я начал reverse-engineering Android-приложения. Я где-то слышал, что они отлично декомпилируются в Java-файлы, а оттуда уже можно взять всю логику работы с лампой. Достать apk было не сложно. Вот тут можно найти apk приложения с Google Play, а вот тут декомпилить в код. Параллельно я уже рассказал своей коллеге об идее и услышал положительный отзыв. Так вот, пока я декомпилил, она нашла сервер на Node.js, который подключается к лампе и дает «ручки» для управления. Я подумал и решил, почему бы и нет. Итак, теперь я умею управлять лампой самостоятельно — половина дела сделано.

imageimage

После этого нужно было выбрать идею.
1. Поместить лампочку за монитор и включать ей цвет под изображение на экране. Я видел несколько таких телевизоров.
2. Включать цвет лампочки утром исходя из погоды.
3. Регулировать яркость света в зависимости от яркости экрана (например, не совсем ярко ночью). Оказалось бесполезным.
4. Поместить лампочку за монитор и включать красный свет, когда ты заходишь в контакт за мемасиками во время работы, например.

Четвертая идея показалась самой полезной. Нас уже было двое в команде и мы ринулись делать. Я писал приложение для все еще OS X на Swift’e, а коллега убирала с северной части лишнее. Про сервер я ничего больше писать не буду, все интересное можно посмотреть вот здесь.

Выбрал OS X и Swift, потому что второе более менее знаю, а для первого давно чесались руки написать что-то, надеюсь хорошо получилось. Итак, приложение должно отслеживать «плохие» сайты и загонять лампочку в краску: включать красный свет. Встроенной в язык такой возможности нет (и хорошо). Ну и пошел в каморку спрашивать у гугла.

image

— Хочу узнать открытые вкладки в браузере с помощью Swift или хотя бы Objective-C.
— Я думаю оно тебе не нужно, вот тебе AppleScript.
— Ну круто, а что это?
— Встроенные скрипты, которые могут управлять системой и обычно их используют для автоматизации.
— Окей, тогда скажи мне как узнать открытые вкладки, например, в Safari.
— Да вот же (ссылка). Тут еще и на другие браузеры есть.
— Ну с этим уже можно работать, спасибо.

Поменяем немножко скрипт.

tell application "System Events" to set frontApp to name of first process whose frontmost is true

if (frontApp = "Safari") then
    using terms from application "Safari"
        tell application frontApp to set currentTabUrl to URL of front document
        tell application frontApp to set currentTabTitle to name of front document
    end using terms from
else if (frontApp = "Google Chrome") then
    using terms from application "Google Chrome"
        tell application frontApp to set currentTabUrl to URL of active tab of front window
        tell application frontApp to set currentTabTitle to title of active tab of front window
    end using terms from
else if (frontApp = "Lumen Taba") then
    return 1
else
    return
end if

return currentTabUrl

Теперь осталось запустить эту штуку в background’e и дело в шляпе.

//run tracker in background mode
let qualityOfServiceClass = QOS_CLASS_BACKGROUND
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
dispatch_async(backgroundQueue, {
    while !self.needStop {
        self.isRunning = true
        var error: NSDictionary?
        
        //run script
        if let scriptObject = NSAppleScript(source: self.scriptText!) {
            if let output: NSAppleEventDescriptor = scriptObject.executeAndReturnError(
                &error) {
                //if browser is active
                if output.stringValue != nil {
                    
                    //this app is active
                    if (output.int32Value == 1) {
                        continue
                    }
                    
                    //if bad url
                    if self.urlValidator.isUrlStringBanned(output.stringValue!) {
                        
                        //bad url isn't changed
                        if self.lastBadUrl == output.stringValue {
                            continue
                        }
                        
                        self.lastBadUrl = output.stringValue
                        NSNotificationCenter.defaultCenter().postNotificationName("BadUrlIsOpened",
                            object: self.lastBadUrl)
                        continue
                    }
                    
                }
                
                
                //the browser is not active
                //turn off lamp if it was on
                if self.lastBadUrl != nil {
                    self.lastBadUrl = nil
                    NSNotificationCenter.defaultCenter().postNotificationName("BadUrlIsClosed", object: nil)
                }

            } else if (error != nil) {
                print("error")
            }
        }
        sleep(self.CHECK_INTERVAL)
    }
    
    self.isRunning = false
})

image
Вот так это делается в Swift.

Теперь тестируем url на его испорченность. В качестве стоп-листа было выбрано использовать regex выражения. Достаточно только домен и все страницы сайта будут заблокированы. Конечно возможно и немножко другие случаи, когда другой сайт будет содержать запрещенный домен, но и тут скорей всего Вы что-то делаете не то (зачем Вы ищете vk.com в Google). Добавление сайтов поместил в настройки с сохранением во встроенный в приложение файл, а сама проверка в коде выглядит вот так:

private func checkUrl(url: NSURL) -> Bool {
    let domain = url.host
    
    //there is no domain
    if (domain == nil) {
        return false
    }
    
    let badRegexes = getBadRegexes()
    for br in badRegexes {
        if matchesForRegexInText(br, text: url.absoluteString) {
            return true
        }
    }
    
    return false
}

private func matchesForRegexInText(regex: String!, text: String!) -> Bool {
    do {
        let regex = try NSRegularExpression(pattern: regex, options: [])
        let nsString = text as NSString
        let results = regex.matchesInString(text,
                                            options: [],
                                            range: NSMakeRange(0, nsString.length))
        return results.count > 0 ? true : false
        
    } catch let error as NSError {
        print("invalid regex: (error.localizedDescription)")
        return false
    }
}

Ты можешь посмотреть весь код в репозитории, а я пока что покажу итоговый результат.

image
image

Жду комментариев и новых идей, как еще круто можно использовать подобную лампочку.

Так же, если Вас заинтересовала статья и Вы хотели бы иметь у себя такого сотрудника, то именно для Вас мое резюме: goo.gl/fYahmH.

В течение 14 дней, со дня публикации данной статьи, вы можете приобрести «Умную лампочку Lumen» с 10%-й скидкой, используя код GEEKT-UL.

Автор: Даджет

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js