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

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

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

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

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

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

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

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

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

— Хочу узнать открытые вкладки в браузере с помощью 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
})
Lumen Taba на страже продуктивности: пишем собственное приложение для умной лампочки
Вот так это делается в 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
}
}

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

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

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

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

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