- PVSM.RU - https://www.pvsm.ru -
Хочу поделиться опытом использования системы для умного дома NooLite [1] совместно с Raspberry Pi Model B (далее RPI) в двухкомнатной квартире.
О системе NooLite неоднократно писали на хабре:
В данной статье я расскажу про:
Возможно, кто-то подумает: «я бы не стал заморачиваться с RPI ради такого простого функционала, — управлять освещением в квартире с мобильного телефона, а реализовал бы все используя пластиковый стаканчик, камешек и ниточку на Arduino с WiFi шилдом или более простой и лаконичной реализации на AVR микроконтроллере».
Но, поскольку уже пылился на полке RPI и одолевало желание сделать «умное» освещение с использованием платформы RPI, решил использовать за основу именно его. Также, возможность использования RPI дает хороший запас для расширения функционала «умного дома».
Некоторое время приглядывался к различным платформам и технологиям умного дома, в итоге выбор на систему NooLite исходя из следующего:
Обратил внимание и на платформу для домашней автоматизации Wiren Board [9] на базе ARM9 с богатыми функциональными возможностями под все мыслимые и не мыслимые нужды, особенно порадовала киллер-фича — радиомодуль на 433 МГц, что в моем случае подходит для управления силовыми блоками NooLite. Но поскольку у меня уже есть RPI, будем отталкиваться от этого.
Для реализации «умного» освещения в квартире мне понадобилось решить следующие задачи:
Пункты 1 и 4-6 могут повторяться в цикле.
Цена вопроса:
Итого: ~27000р + контроллер от 3000р.
Планировка угловой двухкомнатной распашонки П44Т с эркером приведена ниже.
Планируется управлять освещением с помощью NooLite во всех помещениях кроме лоджии, ванной и туалета.
2 точки освещения с релейным режимом (включение/выключение).
Одна не очень яркая точка освещения должна управляться датчиком движения PM111 [16]. Это позволит в темное время суток освещать путь ночному скитальцу в поисках огней ночного голода.
Обе точки освещения должны управляться стационарным выключателем расположенным рядом с входной дверью. Выключатель должен предусматривать сценарий «выключить свет во всей квартире».
Тепловой датчик движения переходит в дежурный режим (начинает срабатывать на движение тепловых объектов) при установке необходимого уровня освещенности помещения и чувствительности. Обычно в светлое время суток нет необходимости мигать светом в коридоре чтобы пройти.
Из инструкции к датчику:
Если освещенность возле датчика PM111 [16] выше установленной регулятором «Освещенность», то датчик находится в режиме ожидания. При этом его ток потребления минимален (менее 1 мкА), а тепловой сенсор движения отключен. Когда освещенность опускается ниже заданного уровня, датчик переходит в дежурный режим.
Свет в туалете и ванной управляется классическим стационарным выключателем. Свет и вентилятор в туалете подключены через реле времени F&F PO-415 [17] (тоже белорусы) на DIN рейке.
В результате замыкания управляющего контакта 6 контакты реле 11, 12 замыкаются. Размыкание управляющего контакта 6 вызывает отсчет установленного времени, по истечении которого работа PO-415 прекращается.
Стационарный коридорный выключатель должен быть кнопочного типа, поскольку вызов сценария предполагает нажатие кнопки (сценарий не имеет состояний ВКЛ/ВЫКЛ).
Также кнопка необходима если нам понадобиться выключить уже включенный датчиком движения свет, когда таймер датчика настроен не выключать свет несколько минут после срабатывания. Клавиша в этом случае не подходит.
Итого по коридору:
3 точки освещения:
Точки освещения управляются 3х кнопочным выключателем (пульт PK311 [20]) расположенным у входа на кухню.
2 точки освещения в релейном режиме (SU111-200 [18]):
Каждая точка освещения управляется 2-мя выключателями:
Возможно, кто-то спросит «почему на балконе не поставить 2х клавишный выключатель как и в гостиной? или почему не поставить во всей квартире кнопки?».
Так уж вышло, сначала предполагалось на балконе установить 3х кнопочный выключатель с одной сценарной кнопкой, но потом передумали при выборе дизайна самих выключателей. Также предполагалось, что в коридоре и на кухне будут кнопки, а в гостиной комнате, спальне и на балконе — клавишные выключатели, чтобы сохранить дизайн.
Позже захотелось диммировать свет выключателем у кровати, поэтому все пошло наперекосяк. Чтобы сохранить дизайн выключателей пришлось объездить множество строительных рынков, посетить дюжину интернет сайтов, об этом далее в разделе «найти и купить подходящие выключатели для пультов [14]».
Секция 1 (кровать)
Обычно силовые блоки располагаются в каждой точке освещения. Одна точка освещения — один силовой блок. В моем сценарии освещения есть одно отступление от традиционной логики. В спальне «секция 1» предполагается установить светильник с двумя силовыми блоками один из которых будет диммироваться.
Секция 2 (эркер)
Помимо стационарных выключателей все точки освещения должны управляться с карманного брелка в качестве резервного пульта и RPI. Для брелка:
Скажу сразу, с интеграцией все просто. У NooLite есть модуль MT1132 [6]. Модуль получает управляющий пакет по UART от некоторого контроллера, в моем случае это RPI, передает команду по радиоканалу на исполнительные устройства (силовые блоки) и отвечает стройкой «OKrn» все описано в инструкции к модулю [22].
Напряжение питания модуля (VCC Uпит) | 2.7 — 5.5 В |
---|---|
диапазон входного напряжения на Rx | 0 — Uпит |
TTL HIGH LVL (логическая единица) при Uпит=5 В | 2 — Uпит (5 В) |
TTL LOW LVL (логический ноль) при Uпит=5 В | 0 — 0.8 В |
TTL HIGH LVL (логическая единица) при Uпит=3.3 В | 2 — 3.3 В |
TTL LOW LVL (логический ноль) при Uпит=3.3 В | 0 — 0.8 В |
Скорость UART | 9600 бод |
Поскольку UART линии RPI работают с TTL уровнями 3.3 В, значит будем использовать 3.3В в качестве U питания модуля.
Можно использовать 3 линии на MT1132: VCC, GND и RX, для передачи управляющего пакета. Я так и делал при отладке, — не читал ответ «OKrn» от MT1132, мне достаточно было наблюдать за индикатором привязываемого силового блока. При успешном принятии команды «привязки» на силовом блоке инициируется частое мерцание встроенного светодиода.
Еще один момент, мощность радиопередатчика при U питания 3.3 В — 3.3 мВт, при U питания 5 В — 5 мВт. Максимальное расстояние до силового блока 70 м.
Управляющий пакет состоит из 12 байт:
ST, B0, B1, B2, B3, B4, B5, B6, B7, B8, CS, SP
ST — стартовый байт, всегда равен 85
B0..B8 — payload (управляющие команды)
CS — контрольная сумма. Младший байт от суммы первых 10 байт (с ST по B8)
SP — стоповый байт
По инструкции выписал необходимые мне управляющие байты:
B1 — управляющая команда со значениями:
B4 — адрес канала (от 0 до 31). Всего 32 канала.
остальные байты по умолчанию за исключением контрольной суммы.
B0 — настройка режима передачи модуля.
Если в B0 передается значение 80 (0x50) значит:
В итоге составил вот такую таблицу [23] с необходимыми мне управляющими пакетами.
Было решено установить слаботочку в электрощит внутреннего монтажа:
Prerequisites:
Подготавливая образ словил прикольную хардварную багу на Macbook air, во время записи образа Raspbian-wheezy под рутом (хотя по мне это фича — дополнительная защита от записи, лишний раз подумаешь, прежде чем перезапишешь данные):
dd bs=1m if=2015-02-16-raspbian-wheezy.img of=/dev/disk2
консоль вернула:
dd: /dev/disk2: Permission denied
Cо снятым lock на SD карте, под рутом и правильными модами на /dev/disk2….
Потом нашел трэд по этой теме [24], кому-то помогало дуть в слот SD на маке, кому-то слотоприкладство. Бить макбук в наше время расточительство, и мне в итоге помог небольшой зазор: если SD карту вставить не до конца, все сработает.
Во время отладки пришлось колхозить, поскольку не было подходящих мама-мама коннекторов.
С учетом того, что мне нужна была обертка для управления силовыми блоками через WEB, возможность делать REST запросы в будущем и UART библиотека из одной коробки, — выбор пал на WebIOPi. [4]
Хотя, хотел собрать OpenHAB из-за крутой архитектуры. Платформа автоматизации описывалась на Хабре [25].
Обязательно буду использовать эту платформу в будущем, а пока для моих «хотелок» достаточно выбранной платформы.
Настройка WebIOPi минимальная
Воспользовавшись инструкциями предоставленными на сайте проекта:
Установка джампера для тестирования UART петли.
Используя ранее составленную таблицу с управляющими пакетами напишем простенький Python скрипт управления модулем из RPI SHELL.
#!/usr/bin/python
import sys, getopt
def main(argv):
ch = ''
cmd = ''
try:
opts, args = getopt.getopt(argv,"h:",["ch=","cmd="])
except getopt.GetoptError:
print 'mt1132.py --ch <channel_number> --cmd <ON/OFF/BIND/UNBIND>'
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print 'mt1132.py --ch <channel_number> --cmd <ON/OFF/BIND/UNBIND>'
sys.exit()
elif opt in ("--ch"):
ch = arg
elif opt in ("--cmd"):
cmd = arg
print 'Channel: ', ch
print 'Command: ', cmd
if cmd=='ON' and ch!='':
if ch=='0':
print 'Switch ON channel 0'
serial.writeBytes([0x55, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00a7, 0x00aa])
elif ch=='1':
print 'Switch ON channel 1'
serial.writeBytes([0x55, 0x50, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00a8, 0x00aa])
elif ch=='2':
print 'Switch ON channel 2'
serial.writeBytes([0x55, 0x50, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00a9, 0x00aa])
elif ch=='3':
print 'Switch ON channel 3'
serial.writeBytes([0x55, 0x50, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00aa, 0x00aa])
elif ch=='4':
print 'Switch ON channel 4'
serial.writeBytes([0x55, 0x50, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00ab, 0x00aa])
elif ch=='5':
print 'Switch ON channel 5'
serial.writeBytes([0x55, 0x50, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00ac, 0x00aa])
elif ch=='6':
print 'Switch ON channel 6'
serial.writeBytes([0x55, 0x50, 0x02, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00ad, 0x00aa])
elif ch=='7':
print 'Switch ON channel 7'
serial.writeBytes([0x55, 0x50, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00ae, 0x00aa])
elif ch=='8':
print 'Switch ON channel 8'
serial.writeBytes([0x55, 0x50, 0x02, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00af, 0x00aa])
elif ch=='9':
print 'Switch ON channel 9'
serial.writeBytes([0x55, 0x50, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00b0, 0x00aa])
elif ch=='10':
print 'Switch ON channel 10'
serial.writeBytes([0x55, 0x50, 0x02, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00b1, 0x00aa])
if cmd=='OFF' and ch!='':
if ch=='0':
print 'Switch OFF channel 0'
serial.writeBytes([0x55, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00a5, 0x00aa])
elif ch=='1':
print 'Switch OFF channel 1'
serial.writeBytes([0x55, 0x50, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00a6, 0x00aa])
elif ch=='2':
print 'Switch OFF channel 2'
serial.writeBytes([0x55, 0x50, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00a7, 0x00aa])
elif ch=='3':
print 'Switch OFF channel 3'
serial.writeBytes([0x55, 0x50, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00a8, 0x00aa])
elif ch=='4':
print 'Switch OFF channel 4'
serial.writeBytes([0x55, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00a9, 0x00aa])
elif ch=='5':
print 'Switch OFF channel 5'
serial.writeBytes([0x55, 0x50, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00aa, 0x00aa])
elif ch=='6':
print 'Switch OFF channel 6'
serial.writeBytes([0x55, 0x50, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00ab, 0x00aa])
elif ch=='7':
print 'Switch OFF channel 7'
serial.writeBytes([0x55, 0x50, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00ac, 0x00aa])
elif ch=='8':
print 'Switch OFF channel 8'
serial.writeBytes([0x55, 0x50, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00ad, 0x00aa])
elif ch=='9':
print 'Switch OFF channel 9'
serial.writeBytes([0x55, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00ae, 0x00aa])
elif ch=='10':
print 'Switch OFF channel 10'
serial.writeBytes([0x55, 0x50, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00ae, 0x00aa])
if cmd=='BIND' and ch!='':
if ch=='0':
print 'BIND channel 0'
serial.writeBytes([0x55, 0x50, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00b4, 0x00aa])
elif ch=='1':
print 'BIND channel 1'
serial.writeBytes([0x55, 0x50, 0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00b5, 0x00aa])
elif ch=='2':
print 'BIND channel 2'
serial.writeBytes([0x55, 0x50, 0x0f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00b6, 0x00aa])
elif ch=='3':
print 'BIND channel 3'
serial.writeBytes([0x55, 0x50, 0x0f, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00b7, 0x00aa])
elif ch=='4':
print 'BIND channel 4'
serial.writeBytes([0x55, 0x50, 0x0f, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00b8, 0x00aa])
elif ch=='5':
print 'BIND channel 5'
serial.writeBytes([0x55, 0x50, 0x0f, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00b9, 0x00aa])
elif ch=='6':
print 'BIND channel 6'
serial.writeBytes([0x55, 0x50, 0x0f, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00ba, 0x00aa])
elif ch=='7':
print 'BIND channel 7'
serial.writeBytes([0x55, 0x50, 0x0f, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00bb, 0x00aa])
elif ch=='8':
print 'BIND channel 8'
serial.writeBytes([0x55, 0x50, 0x0f, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00bc, 0x00aa])
elif ch=='9':
print 'BIND channel 9'
serial.writeBytes([0x55, 0x50, 0x0f, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00bd, 0x00aa])
elif ch=='10':
print 'BIND channel 10'
serial.writeBytes([0x55, 0x50, 0x0f, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00be, 0x00aa])
if cmd=='UNBIND' and ch!='':
if ch=='0':
print 'UNBIND channel 0'
serial.writeBytes([0x55, 0x50, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00ae, 0x00aa])
elif ch=='1':
print 'UNBIND channel 1'
serial.writeBytes([0x55, 0x50, 0x09, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00af, 0x00aa])
elif ch=='2':
print 'UNBIND channel 2'
serial.writeBytes([0x55, 0x50, 0x09, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00b0, 0x00aa])
elif ch=='3':
print 'UNBIND channel 3'
serial.writeBytes([0x55, 0x50, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00b1, 0x00aa])
elif ch=='4':
print 'UNBIND channel 4'
serial.writeBytes([0x55, 0x50, 0x09, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00b2, 0x00aa])
elif ch=='5':
print 'UNBIND channel 5'
serial.writeBytes([0x55, 0x50, 0x09, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00b3, 0x00aa])
elif ch=='6':
print 'UNBIND channel 6'
serial.writeBytes([0x55, 0x50, 0x09, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00b4, 0x00aa])
elif ch=='7':
print 'UNBIND channel 7'
serial.writeBytes([0x55, 0x50, 0x09, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00b5, 0x00aa])
elif ch=='8':
print 'UNBIND channel 8'
serial.writeBytes([0x55, 0x50, 0x09, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00b6, 0x00aa])
elif ch=='9':
print 'UNBIND channel 9'
serial.writeBytes([0x55, 0x50, 0x09, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00b7, 0x00aa])
elif ch=='10':
print 'UNBIND channel 10'
serial.writeBytes([0x55, 0x50, 0x09, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00b8, 0x00aa])
if __name__ == "__main__":
main(sys.argv[1:])
Для управления MT1132 из консоли SHELL выполняем следующие команды
mt1132.py --ch <channel_number> --cmd <ON/OFF/BIND/UNBIND>
Прикручиваем REST API
Фреймворк WebIOPi предусматривает управление через HTTP запросы в стиле REST [28], что облегчает прикручивание мобильных клиентов и упрощает взаимодействие «клиент-сервер».
Копипаст возможностей REST API фреймворка по ссылки выше:
Наш кейс «Call a macro on the server». Описание не жирное, но достаточное для эксперимента:
HTTP POST /macros/(macro)/(args)
Поскольку (macro) еще не подготовлен проверим REST «Get full GPIO state/configuration», а для этого нужно сделать запрос HTTP GET /*.
Открываем любой REST API Client, я использовал DHC клиент для хром браузера. Пробуем выполнить REST запрос получения текущего времени.
Конфигурация WebIOPi (/etc/webiopi/config)
В разделе [DEVICES]:
Добавляем устройство serial (UART GPIO) — это и есть наш модуль MT1132, где
ttyAMA0 — это девайс (порт), который видит ядро Raspbian,
baudrate — это скорость в бодах обмена информации через этот UART интерфейс.
9600 бод / (8 + 1 старт бит + 1 стоп бит) = 960 байт/с.
В разделе [SCRIPTS] (custom scripts):
Дбавляем строку myscrypt = /home/pi/smarthome/python/mt1132.py — для подключения нашего скрипта к фреймворку.
В разделе [REST] (настройки управления GPIO через REST API. Опционально):
gpio-post-value = false — запрещаем изменение логических уровней LOW/HIGH на пинах GPIO через REST запросы;
gpio-post-function = false — запрещаем изменение настройки IN/OUT на пинах GPIO через REST запросы.
Остальные настройки оставляем без изменений.
[COAP]:
Не стал трогать, отключать. Пока представлений не имею, с чем его едят и где он применяется. Зафиксировал только в голове вот эту строку «СoAP — is a specialized web transfer protocol for use with constrained nodes and constrained networks in the Internet of Things, designed for machine-to-machine (M2M) applications such as smart energy and building automation».
Может на Хабре кто-нибудь раскроет полезные кейсы использования.
# Channel 0
@webiopi.macro
def ch0(cmd):
if cmd=='on':
serial.writeBytes([0x55, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00a7, 0x00aa])
webiopi.sleep(1)
resp = 'Channel: 0, Cmd: ' + cmd + ', Status: ' + serial.readString()
if cmd=='off':
serial.writeBytes([0x55, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00a5, 0x00aa])
webiopi.sleep(1)
resp = 'Channel: 0, Cmd: ' + cmd + ', Status: ' + serial.readString()
if cmd=='unbind':
serial.writeBytes([0x55, 0x50, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00ae, 0x00aa])
webiopi.sleep(1)
resp = 'Channel: 0, Cmd: ' + cmd + ', Status: ' + serial.readString()
if cmd=='bind':
serial.writeBytes([0x55, 0x50, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00b4, 0x00aa])
webiopi.sleep(1)
resp = 'Channel: 0, Cmd: ' + cmd + ', Status: ' + serial.readString()
return resp
Отправляем REST запрос «привязки адреса 3-го канала NooLite MT1132 к силовому блоку на котором инициирована привязка» через DHC.
При успешной отправке управляющего пакета модуль MT1132 ответит по UART TX в GPIO UART RX «OK». Силовой блок в случае успеха запомнит адрес канала и замигает интенсивно встроенным зеленым светодиодом.
Изначально я не планировал писать приложение под андройд, в силу того что представления не имел, предполагал ограничиться браузером. Потом случайно забрел на канал Start Android [29]. Автор Дмитрий подробно рассказывает вместе с Андрюхой, как быстро стартануть свой первый проект под Андройд платформы. Огромное спасибо автору за проект и вложенный труд!
Посмотрев и выполнив не более 20 уроков я приступил к созданию своего простого приложения для управления освещением. Для разработки использовал IDE Android Studio, как подсказывает гугл, — based on IntelliJ IDEA.
Интерфейс
Получился очень аскетичный интерфейс:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/hl7"
android:padding="2dp"
android:clickable="false">
<!-- Шапка-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal">
<TextView
android:id="@+id/r1c1"
android:textSize="18sp"
android:layout_width="110dp"
android:layout_height="match_parent"
android:padding="4dp"
android:layout_margin="1dp"
android:text="Помещение"
android:background="@color/hl4"
android:layout_weight="1"
android:gravity="center"
android:textColor="@color/white" />
<TextView
android:textColor="@color/white"
android:textSize="18sp"
android:id="@+id/r1c2"
android:layout_width="120dp"
android:layout_height="match_parent"
android:padding="4dp"
android:text="Точка освещения"
android:layout_margin="1dp"
android:background="@color/hl4"
android:layout_weight="2"
android:gravity="center"/>
<TextView
android:textColor="@color/white"
android:textSize="18sp"
android:id="@+id/r1c3"
android:layout_width="150dp"
android:layout_height="match_parent"
android:padding="4dp"
android:text="Управление"
android:layout_margin="1dp"
android:background="@color/hl4"
android:layout_weight="3"
android:gravity="center"/>
</LinearLayout>
<!-- кухня -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="110dp"
android:layout_height="match_parent"
android:textColor="@color/black"
android:textSize="16sp"
android:text="@string/room1txt"
android:id="@+id/room1"
android:layout_weight="1"
android:layout_margin="1dp"
android:padding="4dp"
android:gravity="center"
android:background="@color/holotheme_color"
android:textStyle="bold" />
<LinearLayout
android:orientation="vertical"
android:background="@color/hl8"
android:layout_width="120dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:layout_margin="1dp"
android:gravity="center|top">
<TextView
android:layout_width="match_parent"
android:textColor="@color/hl9"
android:layout_height="36dp"
android:text="@string/place1txt"
android:id="@+id/r1switch1"
android:textSize="13sp"
android:padding="4dp"
android:gravity="center_vertical|left"
android:background="@drawable/hover1"
android:clickable="true"/>
<TextView
android:textSize="13sp"
android:layout_width="match_parent"
android:layout_height="36dp"
android:textColor="@color/hl9"
android:text="@string/place5txt"
android:id="@+id/r1switch2"
android:padding="4dp"
android:gravity="center_vertical|left"
android:background="@drawable/hover1"
android:clickable="true"/>
<TextView
android:textSize="13sp"
android:layout_width="match_parent"
android:layout_height="36dp"
android:textColor="@color/hl9"
android:text="@string/place2txt"
android:id="@+id/r1switch3"
android:padding="4dp"
android:gravity="center_vertical|left"
android:background="@drawable/hover1"
android:clickable="true"/>
</LinearLayout>
<LinearLayout
android:background="@color/hl8"
android:orientation="vertical"
android:layout_width="150dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:gravity="center"
android:layout_margin="1dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="36dp">
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="ВКЛ"
android:id="@+id/r1b1on" />
<Button
style="?android:attr/buttonStyleSmall"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="ВЫКЛ"
android:id="@+id/r1b1off" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="36dp">
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="match_parent"
android:text="ВКЛ"
android:id="@+id/r1b2on" />
<Button
style="?android:attr/buttonStyleSmall"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="ВЫКЛ"
android:id="@+id/r1b2off" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="36dp">
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="ВКЛ"
android:id="@+id/r1b3on" />
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="match_parent"
android:text="ВЫКЛ"
android:id="@+id/r1b3off" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<!-- Гостиная -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<TextView
android:layout_width="110dp"
android:layout_height="match_parent"
android:textSize="16sp"
android:text="@string/room2txt"
android:id="@+id/room2"
android:layout_weight="1"
android:layout_margin="1dp"
android:padding="4dp"
android:gravity="center"
android:background="@color/holotheme_color"
android:textColor="@color/black"
android:textStyle="bold"/>
<TextView
android:layout_width="120dp"
android:layout_height="match_parent"
android:textSize="13sp"
android:text="@string/place1txt"
android:textColor="@color/hl9"
android:id="@+id/r2switch1"
android:layout_weight="2"
android:layout_margin="1dp"
android:padding="4dp"
android:gravity="center|left"
android:background="@color/hl8"/>
<LinearLayout
android:background="@color/hl8"
android:orientation="horizontal"
android:layout_width="150dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:gravity="center"
android:layout_margin="1dp">
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:layout_weight="1"
android:text="ВКЛ"
android:id="@+id/r2b1on" />
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="36dp"
android:text="ВЫКЛ"
android:id="@+id/r2b1off" />
</LinearLayout>
</LinearLayout>
<!-- Балкон -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<TextView
android:layout_width="110dp"
android:layout_height="match_parent"
android:textSize="16sp"
android:text="@string/room3txt"
android:id="@+id/room3"
android:layout_weight="1"
android:layout_margin="1dp"
android:padding="4dp"
android:textColor="@color/black"
android:gravity="center"
android:background="@color/holotheme_color"
android:textStyle="bold"/>
<TextView
android:layout_width="120dp"
android:layout_height="match_parent"
android:textSize="13sp"
android:textColor="@color/hl9"
android:text="@string/place1txt"
android:id="@+id/r3switch1"
android:layout_weight="2"
android:layout_margin="1dp"
android:padding="4dp"
android:gravity="center|left"
android:background="@color/hl8"
android:clickable="true"/>
<LinearLayout
android:background="@color/hl8"
android:orientation="horizontal"
android:layout_width="150dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:gravity="center"
android:layout_margin="1dp">
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:layout_weight="1"
android:text="ВКЛ"
android:id="@+id/r3b1on" />
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:layout_weight="1"
android:text="ВЫКЛ"
android:id="@+id/r3b1off" />
</LinearLayout>
</LinearLayout>
<!-- Комната с эркером -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="110dp"
android:layout_height="match_parent"
android:textSize="16sp"
android:text="@string/room4txt"
android:id="@+id/room4"
android:layout_weight="1"
android:layout_margin="1dp"
android:padding="4dp"
android:gravity="center"
android:background="@color/holotheme_color"
android:textColor="@color/black"
android:textStyle="bold" />
<LinearLayout
android:orientation="vertical"
android:background="@color/hl8"
android:layout_width="120dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:layout_margin="1dp"
android:gravity="center">
<TextView
android:layout_width="match_parent"
android:layout_height="37dp"
android:text="@string/place6txt"
android:textColor="@color/hl9"
android:id="@+id/r4switch1"
android:textSize="13sp"
android:padding="4dp"
android:gravity="center_vertical|left"
android:background="@drawable/hover1"
android:clickable="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="37dp"
android:text="@string/place8txt"
android:textColor="@color/hl9"
android:id="@+id/r4switch3"
android:textSize="13sp"
android:padding="4dp"
android:gravity="center_vertical|left"
android:background="@drawable/hover1"
android:clickable="true"/>
<TextView
android:textSize="13sp"
android:layout_width="match_parent"
android:textColor="@color/hl9"
android:layout_height="37dp"
android:text="@string/place7txt"
android:id="@+id/r4switch2"
android:padding="4dp"
android:gravity="center_vertical|left"
android:background="@drawable/hover1"
android:clickable="true"/>
</LinearLayout>
<LinearLayout
android:background="@color/hl8"
android:orientation="vertical"
android:layout_width="150dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:gravity="center"
android:layout_margin="1dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="37dp">
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="ВКЛ"
android:id="@+id/r4b1on" />
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="match_parent"
android:text="ВЫКЛ"
android:id="@+id/r4b1off" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="36dp">
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="ВКЛ"
android:id="@+id/r4b3on" />
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="match_parent"
android:text="ВЫКЛ"
android:id="@+id/r4b3off" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="36dp">
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="ВКЛ"
android:id="@+id/r4b2on" />
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="match_parent"
android:text="ВЫКЛ"
android:id="@+id/r4b2off" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<!-- Коридор -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="110dp"
android:layout_height="match_parent"
android:textSize="16sp"
android:text="@string/room5txt"
android:id="@+id/room5"
android:layout_weight="1"
android:layout_margin="1dp"
android:padding="4dp"
android:gravity="center"
android:textColor="@color/black"
android:background="@color/holotheme_color"
android:textStyle="bold" />
<LinearLayout
android:orientation="vertical"
android:background="@color/hl8"
android:layout_width="120dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:layout_margin="1dp"
android:gravity="center">
<TextView
android:layout_width="match_parent"
android:layout_height="36dp"
android:text="@string/place3txt"
android:textColor="@color/hl9"
android:id="@+id/r5switch1"
android:textSize="13sp"
android:padding="4dp"
android:gravity="center_vertical|left"
android:background="@drawable/hover1"
android:clickable="true"/>
<TextView
android:textSize="13sp"
android:layout_width="match_parent"
android:layout_height="37dp"
android:textColor="@color/hl9"
android:text="@string/place4txt"
android:id="@+id/r5switch2"
android:padding="4dp"
android:gravity="center_vertical|left"
android:background="@drawable/hover1"
android:clickable="true"/>
</LinearLayout>
<LinearLayout
android:background="@color/hl8"
android:orientation="vertical"
android:layout_width="150dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:gravity="center"
android:layout_margin="1dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="36dp">
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="ВКЛ"
android:id="@+id/r5b1on" />
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="match_parent"
android:text="ВЫКЛ"
android:id="@+id/r5b1off" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="37dp">
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="ВКЛ"
android:id="@+id/r5b2on" />
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="match_parent"
android:text="ВЫКЛ"
android:id="@+id/r5b2off" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
К кнопкам привязаны методы onClick.
@Override
public void onClick(View v) {
// define the button switch that invoked the listener by id
switch (v.getId()) {
// Buttons room1 кухня
case R.id.r1b1on: // основной
Toast.makeText(this, getString(R.string.bon)+" '"+getString(R.string.room1txt)+" > "+r1sw1.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch4url) + "on";
new ParseTask().execute();
break;
Switch определяет ID view элемента кнопки, выводит TOAST сообщение на экран и делает HTTP запрос на RPI через HttpURLConnection внутри AsyncTask (вызов ParseTask().execute();).
Взаимодействие с backend
HttpURLConnection — класс для взаимодействия по HTTP протоколу.
Метод doInBackground класса AsyncTask — выполняет тяжелые задачи в отдельном бэкграунд потоке и возвращает результат обратно в UI поток.
HttpURLConnection выполняется в методе doInBackground.
Такой прием часто встречается в интернете для реализации обмена данными через HTTP протокол.
webiopiurl = getString(R.string.ch4url) + "on";
Подставляет константу из файла strings.xml в ресурсах проекта
<string name="ch4url">http://192.168.1.154:8000/macros/ch4/</string>
Таким образом полный URL для включения канала 4 выглядит так
http://192.168.1.154:8000/macros/ch4/on
// HTTP Query to backend in REST style
private class ParseTask extends AsyncTask<Void, Void, String> {
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
String result = "";
String BASIC_AUTH = "Basic "
+ Base64.encodeToString((getString(R.string.login) + ":" + getString(R.string.pwd)).getBytes(), Base64.NO_WRAP);
@Override
protected String doInBackground(Void... params) {
// выполняем запрос в REST стиле
try {
URL url = new URL(webiopiurl);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Authorization", BASIC_AUTH);
urlConnection.connect();
// получаем ответ от backend webiopi
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
result = buffer.toString();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
package ru.bbq.smarthome_App;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class MainActivity extends ActionBarActivity implements View.OnClickListener {
// Add logger
public static String LOG_TAG = "my_log";
public static String webiopiurl = "";
// switch buttons
TextView r1sw1;
TextView r1sw2;
TextView r1sw3;
TextView r2sw1;
TextView r3sw1;
TextView r4sw1;
TextView r4sw2;
TextView r4sw3;
TextView r5sw1;
TextView r5sw2;
// ON OFF buttons
Button r1b1on;
Button r1b1off;
Button r1b2on;
Button r1b2off;
Button r1b3on;
Button r1b3off;
Button r2b1on;
Button r2b1off;
Button r3b1on;
Button r3b1off;
Button r4b1on;
Button r4b1off;
Button r4b2on;
Button r4b2off;
Button r4b3on;
Button r4b3off;
Button r5b1on;
Button r5b1off;
Button r5b2on;
Button r5b2off;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// find View-elements and buttons
r1sw1 = (TextView) findViewById(R.id.r1switch1); // room1switch1
r1sw2 = (TextView) findViewById(R.id.r1switch2); // room1switch2
r1sw3 = (TextView) findViewById(R.id.r1switch3); // room1switch3
r2sw1 = (TextView) findViewById(R.id.r2switch1); // room2switch1
r3sw1 = (TextView) findViewById(R.id.r3switch1); // room3switch1
r4sw1 = (TextView) findViewById(R.id.r4switch1); // room4switch1
r4sw2 = (TextView) findViewById(R.id.r4switch2); // room4switch2
r4sw3 = (TextView) findViewById(R.id.r4switch3); // room4switch3
r5sw1 = (TextView) findViewById(R.id.r5switch1); // room5switch1
r5sw2 = (TextView) findViewById(R.id.r5switch2); // room5switch2
r1b1on = (Button) findViewById(R.id.r1b1on); // room1 button1 ON
r1b1off = (Button) findViewById(R.id.r1b1off); // room1 button1 OFF
r1b2on = (Button) findViewById(R.id.r1b2on); // room1 button2 ON
r1b2off = (Button) findViewById(R.id.r1b2off); // room1 button2 OFF
r1b3on = (Button) findViewById(R.id.r1b3on); // room1 button3 ON
r1b3off = (Button) findViewById(R.id.r1b3off); // room1 button3 OFF
r2b1on = (Button) findViewById(R.id.r2b1on); // room2 button1 ON
r2b1off = (Button) findViewById(R.id.r2b1off); // room2 button1 OFF
r3b1on = (Button) findViewById(R.id.r3b1on); // room3 button1 ON
r3b1off = (Button) findViewById(R.id.r3b1off); // room3 button1 OFF
r4b1on = (Button) findViewById(R.id.r4b1on); // room4 button1 ON
r4b1off = (Button) findViewById(R.id.r4b1off); // room4 button1 OFF
r4b2on = (Button) findViewById(R.id.r4b2on); // room4 button2 ON
r4b2off = (Button) findViewById(R.id.r4b2off); // room4 button2 OFF
r4b3on = (Button) findViewById(R.id.r4b3on); // room4 button3 ON
r4b3off = (Button) findViewById(R.id.r4b3off); // room4 button3 OFF
r5b1on = (Button) findViewById(R.id.r5b1on); // room5 button1 ON
r5b1off = (Button) findViewById(R.id.r5b1off); // room5 button1 OFF
r5b2on = (Button) findViewById(R.id.r5b2on); // room5 button2 ON
r5b2off = (Button) findViewById(R.id.r5b2off); // room5 button2 OFF
//assign listeners to buttons
r1b1on.setOnClickListener(this);
r1b1off.setOnClickListener(this);
r1b2on.setOnClickListener(this);
r1b2off.setOnClickListener(this);
r1b3on.setOnClickListener(this);
r1b3off.setOnClickListener(this);
r2b1on.setOnClickListener(this);
r2b1off.setOnClickListener(this);
r3b1on.setOnClickListener(this);
r3b1off.setOnClickListener(this);
r4b1on.setOnClickListener(this);
r4b1off.setOnClickListener(this);
r4b2on.setOnClickListener(this);
r4b2off.setOnClickListener(this);
r4b3on.setOnClickListener(this);
r4b3off.setOnClickListener(this);
r5b1on.setOnClickListener(this);
r5b1off.setOnClickListener(this);
r5b2on.setOnClickListener(this);
r5b2off.setOnClickListener(this);
}
// Define On ClickView method
@Override
public void onClick(View v) {
// define the button switch that invoked the listener by id
switch (v.getId()) {
// Buttons room1 кухня
case R.id.r1b1on: // основной
Toast.makeText(this, getString(R.string.bon)+" '"+getString(R.string.room1txt)+" > "+r1sw1.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch4url) + "on";
new ParseTask().execute();
break;
case R.id.r1b1off: // основной
Toast.makeText(this, getString(R.string.boff)+" '"+getString(R.string.room1txt)+" > "+r1sw1.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch4url) + "off";
new ParseTask().execute();
break;
case R.id.r1b2on: // кухня точечный
Toast.makeText(this, getString(R.string.bon)+" '"+getString(R.string.room1txt)+" > "+r1sw2.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch3url) + "on";
new ParseTask().execute();
break;
case R.id.r1b2off: // кухня точечный
Toast.makeText(this, getString(R.string.boff)+" '"+getString(R.string.room1txt)+" > "+r1sw2.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch3url) + "off";
new ParseTask().execute();
break;
case R.id.r1b3on: // LED кухня
Toast.makeText(this, getString(R.string.bon)+" '"+getString(R.string.room1txt)+" > "+r1sw3.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch2url) + "on";
new ParseTask().execute();
break;
case R.id.r1b3off: // LED кухня
Toast.makeText(this, getString(R.string.boff)+" '"+getString(R.string.room1txt)+" > "+r1sw3.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch2url) + "off";
new ParseTask().execute();
break;
// Buttons room2 гостиная
case R.id.r2b1on:
Toast.makeText(this, getString(R.string.bon)+" '"+getString(R.string.room2txt)+" > "+r2sw1.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch6url) + "on";
new ParseTask().execute();
break;
case R.id.r2b1off:
Toast.makeText(this, getString(R.string.boff)+" '"+getString(R.string.room2txt)+" > "+r2sw1.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch6url) + "off";
new ParseTask().execute();
break;
// Buttons room3 балкон
case R.id.r3b1on:
Toast.makeText(this, getString(R.string.bon)+" '"+getString(R.string.room3txt)+" > "+r3sw1.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch5url) + "on";
new ParseTask().execute();
break;
case R.id.r3b1off:
Toast.makeText(this, getString(R.string.boff)+" '"+getString(R.string.room3txt)+" > "+r3sw1.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch5url) + "off";
new ParseTask().execute();
break;
// Buttons room4 bedroom
case R.id.r4b1on: // над кроватью релейный режим
Toast.makeText(this, getString(R.string.bon)+" '"+getString(R.string.room4txt)+" > "+r4sw1.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch8url) + "on";
new ParseTask().execute();
break;
case R.id.r4b1off: // над кроватью релейный режим
Toast.makeText(this, getString(R.string.boff)+" '"+getString(R.string.room4txt)+" > "+r4sw1.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch8url) + "off";
new ParseTask().execute();
break;
case R.id.r4b2on: // у эркера в спальне
Toast.makeText(this, getString(R.string.bon)+" '"+getString(R.string.room4txt)+" > "+r4sw2.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch7url) + "on";
new ParseTask().execute();
break;
case R.id.r4b2off: // у эркера в спальне
Toast.makeText(this, getString(R.string.boff)+" '"+getString(R.string.room4txt)+" > "+r4sw2.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch7url) + "off";
new ParseTask().execute();
break;
case R.id.r4b3on: // над кроватью dimmer
Toast.makeText(this, getString(R.string.bon)+" '"+getString(R.string.room4txt)+" > "+r4sw3.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch9url) + "on";
new ParseTask().execute();
break;
case R.id.r4b3off: // над кроватью dimmer
Toast.makeText(this, getString(R.string.boff)+" '"+getString(R.string.room4txt)+" > "+r4sw3.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch9url) + "off";
new ParseTask().execute();
break;
// Buttons room5 corridor
case R.id.r5b1on:
Toast.makeText(this, getString(R.string.bon)+" '"+getString(R.string.room5txt)+" > "+r5sw1.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch1url) + "on";
new ParseTask().execute();
break;
case R.id.r5b1off:
Toast.makeText(this, getString(R.string.boff)+" '"+getString(R.string.room5txt)+" > "+r5sw1.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch1url) + "off";
new ParseTask().execute();
break;
case R.id.r5b2on:
Toast.makeText(this, getString(R.string.bon)+" '"+getString(R.string.room5txt)+" > "+r5sw2.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch0url) + "on";
new ParseTask().execute();
break;
case R.id.r5b2off:
Toast.makeText(this, getString(R.string.boff)+" '"+getString(R.string.room5txt)+" > "+r5sw2.getText()+"'", Toast.LENGTH_SHORT).show();
webiopiurl = getString(R.string.ch0url) + "off";
new ParseTask().execute();
break;
}
}
// HTTP Query to backend in REST style
private class ParseTask extends AsyncTask<Void, Void, String> {
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
String result = "";
String BASIC_AUTH = "Basic "
+ Base64.encodeToString((getString(R.string.login) + ":" + getString(R.string.pwd)).getBytes(), Base64.NO_WRAP);
@Override
protected String doInBackground(Void... params) {
// выполняем запрос в REST стиле
try {
URL url = new URL(webiopiurl);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Authorization", BASIC_AUTH);
urlConnection.connect();
// получаем ответ от backend webiopi
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
result = buffer.toString();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
@Override
protected void onPostExecute(String str) {
super.onPostExecute(str);
// ответ обрабатываем, как простую строку plain text (не JSON)
// выводим результат в log
Log.d(LOG_TAG, str);
// делаем TOAST - выводим ответ webiopi вместе со статусом модуля MT1132
Toast.makeText(getApplicationContext(), str, Toast.LENGTH_SHORT).show();
}
}
}
Исходя из сценария освещения в данном проекте используются стационарные встраиваемые пульты/выключатели NooLite клавишные и кнопочные, то нужно предусмотреть возможность установки выключателей с 3-мя модулями (кнопками/клавишами) сохранив дизайн выключателей (все выключатели должны выглядеть одинаково).
При выборе выключателей предусмотреть возможность:
Под данные условия подощли выключатели bticino livinglight. На фото ниже собранные модули с пультом NooLite.
Силовой блок на потолке во время отладки
Отладка на месте
Электрощит с размещенной внутри слаботочкой
Спасибо за внимание. Хорошего дня!
Автор: 2b3q
Источник [30]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/diy/95780
Ссылки в тексте:
[1] NooLite: http://www.noo.com.by/sistema-noolite.html
[2] NooLite — система радиоуправления освещением, или первый шаг к умному дому: http://habrahabr.ru/company/boxowerview/blog/165131
[3] NooLite-2, или умный дом для чайников: http://habrahabr.ru/company/boxowerview/blog/168039/
[4] WebIOPi: https://code.google.com/p/webiopi/
[5] Raspbian: https://www.raspberrypi.org/downloads/
[6] модуль MT1132 NooLite: http://www.noo.com.by/modul_mt1132.html
[7] RPI: https://ru.wikipedia.org/wiki/Raspberry_Pi
[8] ратифицированная ГКРЧ частота 433 МГц: http://www.lpdnet.ru/index.php?go=Pages&in=view&id=28
[9] Wiren Board: http://habrahabr.ru/company/contactless/blog/213243/
[10] определить оптимальный сценарий освещения в двухкомнатной квартире: #block1
[11] определить метод интеграции с RPI и размещения слаботочки: #block2
[12] выбрать обертку для управления: #block3
[13] нарисовать общую архитектуру взаимодействия: #arch
[14] найти и купить подходящие выключатели для пультов: #block4
[15] разработать мобильное приложение под Android: #block5
[16] PM111: http://www.noo.com.by/pm111.html
[17] реле времени F&F PO-415: https://yadi.sk/i/p2YHdczLiNNNK
[18] SU111-200: http://noo.com.ru/magazin/product/silovoy-blok-sl111-200-nootehnika-noolayt-3
[19] PK313: http://noo.com.ru/magazin/product/pult-rk-312-nootehnika-noolayt
[20] PK311: http://noo.com.ru/magazin/product/pult-rk-311-nootehnika-noolayt
[21] PK314: http://noo.com.ru/magazin/product/pult-rk-313-nootehnika-noolayt
[22] инструкции к модулю: http://www.noo.com.by/assets/files/PDF/MT1132.pdf
[23] таблицу: https://yadi.sk/i/wZdJ4mW-iNMa6
[24] трэд по этой теме: https://www.raspberrypi.org/forums/viewtopic.php?f=5&t=5561
[25] Платформа автоматизации описывалась на Хабре: http://habrahabr.ru/post/232969/
[26] установливаем framework WebIOPi: https://code.google.com/p/webiopi/wiki/INSTALL
[27] настраиваем UART: https://code.google.com/p/webiopi/wiki/Tutorial_Serial
[28] WebIOPi предусматривает управление через HTTP запросы в стиле REST: https://code.google.com/p/webiopi/wiki/RESTAPI
[29] Start Android: https://www.youtube.com/user/vitaxafication
[30] Источник: http://geektimes.ru/post/260046/
Нажмите здесь для печати.