الأتمتة مع Pebble مريحة ، Noolite مستقرة وبأسعار معقولة esp8266

منذ المقالة الأخيرة (استمر الرابط لمدة عام تقريبًا. وخلال هذا العام ، أعدت التفكير في بعض الأشياء ، وشكل الإنترنت شيئًا مثل إنترنت الأشياء :) → إنترنت الأشياء).

سأحاول أن ألخص جزءًا جديدًا من المعرفة المتراكمة ، وأصف أين أسعى وما أريد تحقيقه ← أطلب منك قراءته.

Noolite F v2.0


في العنوان ، حصلت على الكلمات: حصاة ونوليت. دعنا ننتقل إليهم!
ما زلت أدير مع حصاة بلدي ضوء المرآب والجراج والبوابة. لقد تم بالفعل كتابة الكثير من المعلومات المفيدة حول النولايت ، ويظهر البحث مقالات جديدة.

بالإضافة إلى وحدات الجيل الأول من نظام noolite ، لدي وحدات جديدة: وحدة طاقة SLF-1-200 (nooLite-F) مع التغذية المرتدة ( وتشفير الجيل الجديد ).

الصورة

كتلة الطاقة SB-1-150

الصورة

ومحول USB محدث MTRF-64 USB.

الصورة

كل الضوء في بيتي على نظام noolite.

حتى وقت قريب ، كان لدي محول USB من الجيل الأول مع 16 جهازًا والآن 64 قناة (MTRF-64 USB) في "تشنج النظام الأساسي للمنزل" ، وأيضًا لأجهزة الجيل الجديد ذات التعليقات (noolite F). لكن التكنولوجيا تسير في الاتجاه الصحيح ، مخلقة أجهزة جديدة وحديثة.

هناك خياران أهم للأجهزة الجديدة: الملاحظات ومبدأ تحديد الأجهزة حسب العناوين: المعرّف. الآن ليس عليك كتابة الأجهزة لقناة 1 والتحكم في القناة. الآن يمكنك الوصول إلى جهاز معين في قناة واحدة عن طريق معرفه وإرسال أمر تنفيذ إليه.

وثائق الجيل الجديد متاحة على موقع الشركة المصنعة.

كل شيء يعمل من خلال المنفذ التسلسلي باستخدام رمز بيثون.
# -*- coding: utf-8 -*- #!/usr/bin/env python import serial import time class NooLiteCommand: def __init__(self, ch, cmd, mode=0, ctr=0, res=0, fmt=0, d0=0, d1=0, d2=0, d3=0, id0=0, id1=0, id2=0, id3=0): self.st = 171 self.mode = mode self.ctr = ctr self.res = res self.ch = ch self.cmd = cmd self.fmt = fmt self.d0 = d0 self.d1 = d1 self.d2 = d2 self.d3 = d3 self.id0 = id0 self.id1 = id1 self.id2 = id2 self.id3 = id3 self.sp = 172 @property def crc(self): crc = sum([ self.st, self.mode, self.ctr, self.res, self.ch, self.cmd, self.fmt, self.d0, self.d1, self.d2, self.d3, self.id0, self.id1, self.id2, self.id3, ]) return crc if crc < 256 else divmod(crc, 256)[1] def to_bytes(self): return bytearray([ self.st, self.mode, self.ctr, self.res, self.ch, self.cmd, self.fmt, self.d0, self.d1, self.d2, self.d3, self.id0, self.id1, self.id2, self.id3, self.crc, self.sp ]) class NooliteSerial: def __init__(self, tty_name): self.tty = self._get_tty(tty_name) def on(self, ch): self.send_command(ch, 2, 2, 0) pass def off(self, ch): self.send_command(ch, 0, 2, 0) pass def status(self, ch): m = self.send_command(ch, 128, 2, 0) pass def send_command(self, ch, cmd, mode=0, ctr=0, res=0, fmt=0, d0=0, d1=0, d2=0, d3=0, id0=0, id1=0, id2=0, id3=0): command = NooLiteCommand(ch, cmd, mode, ctr, res, fmt, d0, d1, d2, d3, id0, id1, id2, id3) self.tty.write(command.to_bytes()) while True: bytes_response = list(self.tty.read(117)) if bytes_response: all_responses.append(bytes_response) if bytes_response[3] == 0: break else: break return all_responses @staticmethod def _get_tty(tty_name): serial_port = serial.Serial(tty_name, timeout=0.1) if not serial_port.is_open: serial_port.open() serial_port.flushInput() serial_port.flushOutput() return serial_port noo_serial = NooliteSerial('/dev/ttyUSB0') #ch, cmd, mode, ctr #noo_serial.send_command(1, 15, 2, 0) #    1 #noo_serial.send_command(0, 4, 2, 0) #switch #noo_serial.send_command(0, 2, 2, 0) #turn on #noo_serial.send_command(0, 3, 2, 0) #   #noo_serial.send_command(0, 0, 2, 0) #turn off #noo_serial.send_command(0, 15, 2, 0) #  #noo_serial.send_command(0, 128, 2, 0,0,1) #CMD_Read_State + fmt = 1 #noo_serial.on(0) #noo_serial.status(0) #noo_serial.off(0) #noo_serial.off(0) #noo_serial.status(0) #noo_serial.send_command(ch=0,ctr=8, cmd=4, id0=0,id1=0,id2=48,id3=114) #switch noolite ID 0.0.48.114 


باستخدام الوظائف اللازمة في الوقت المناسب ، يمكننا التحكم في كتل noolite وتلقي الحالة من تلك الجديدة. نظرًا لأن لدي 99 ٪ من هذه الكتل القديمة ، يبقى لي استخدام المخطط القديم لكتابة كتلة واحدة إلى قناة واحدة ، مع الأخذ في الاعتبار حقيقة أن محول USB يدعم كلاً من الكتل القديمة والجديدة (بفضل المطورين للتوافق دون رقص الدف). على الفور ، يمكنك إدارة وتلقي حالة كتل جديدة وإدارة القديمة.

حتى وقت قريب ، لم يكن هناك زر ضغط واحد في المنزل. اضطررت إلى إضافة ضوء إلى المرآب (وصلت للتو لترتيب الأشياء: D) ، كما ظهر مفتاح في الإضاءة الخلفية لمرآة الماكياج. مع العلم أن هناك وحدة طاقة SB-1-150 ، قمت بتعيين المفتاح العادي وتوصيل الوحدة. كان الضوء الخلفي للمرآة مصنوعًا من لوحة بيضاء ، لمبات إضاءة 3 وات 4000 ك ، ضوء أبيض. SB-1-150 فريد من نوعه من حيث أنه يمكن وضعه في صندوق مفتاح الجدار (التبديل) في سياق الدائرة الحالية وعن طريق توصيل مفتاح الضغط على الزر بالوحدة نفسها.

بالضبط ما تحتاجه فتاتي للماكياج :)
الصورة

حصاة


عندما بدأت المشاركة في الأتمتة ، كان أحد العوامل الرئيسية: الإدارة المختصة والملائمة.

يبدو أنه من السهل التحكم في الهاتف الذكي ، ولكن ... وليس من المناسب تحميل التطبيق في كل مرة ، حيث توجد أزرار صغيرة غير مريحة ، أو إعلانات على اليسار ، أو حتى تصل إلى الضغط على الزر ... تختفي كل الرغبة. يختفي التحكم الصوتي ، لأنه أيضًا غير مريح وغريب :) - دعه يبقى في مؤامرات أفلام الخيال العلمي.

الصورة

وقمت بحل المشكلة بطريقة أخرى - من خلال ساعة اليد ، التي دائمًا ما لا تشغل مساحة وتجمع بين جميع وسائل الراحة والتنقل وسرعة التحكم. عموما - بيبل على قيد الحياة! ولكن الشيء الأكثر أهمية هو أنه ، على مدار الساعة ، لا يزال بإمكانك كتابة التطبيقات - تطبيقاتك الخاصة ، لإدارة أنظمة الأتمتة الخاصة بك. إنها في الواقع قنبلة.

حصاة على قيد الحياة!

لم تؤثر مأساة إغلاق شركة pebble.com (اشترت Fitbit جميع مواقع pebble.com لبراءات الاختراع) على أدائها وأدائها. في الآونة الأخيرة كان هناك تحديث لـ ios و android - تم إلغاء ربط الساعة من خدمات سحابة حصاة (في حالة إنهاء الدعم) والتفويض.

بصريا - لم يتغير شيء ، لكن الخدمة تبقى : cloudpebble.net - WTF؟ هذا شيء مفيد للغاية. إذا كان بإمكانك كتابة التعليمات البرمجية في JS (وليس هناك رغبة لقضاء الكثير من الوقت على C ++) - يرجى الترحيب على متن الطائرة :) - تسمح لك الحصاة السحابية "بإلقاء" التطبيق بسرعة. حسنًا هكذا فعلت ذلك. بالطبع ، لا ينبغي مقارنة أداء JS مع C ++ (هذا مقدس) ، تعثرت. نعم فعلا!

كود شبيبة سحابة بيبل للعمل مع API
 var UI = require('ui'); var ajax = require('ajax'); var noolite = [ ['','http://your-home-server-ip-address:1183/mqtt/gate/slidegate', 'images/gate.png'], ['','http://your-home-server-ip-address:1183/mqtt/gate/garage', 'images/door.png'], ['!','http://your-home-server-ip-address:1183/noolite/switch/103', 'images/light.png'], [' ','http://your-home-server-ip-address:1183/noolite/switch/100', 'images/system2.png'], ['1  ','', 'images/light.png'], ['2  ','', 'images/light.png'], [' 1','http://your-home-server-ip-address:1183/noolite/switch/101', 'images/light.png'], [' 2','http://your-home-server-ip-address:1183/noolite/switch/102', 'images/light.png'], ['','', 'images/water.png'], ['','http://your-home-server-ip-address:1183/admin/system/1', 'images/system1.png'], ]; var water = [ [' ','http://your-home-server-ip-address:1183/admin/poliv/1', 'images/water.png'], [' ','http://your-home-server-ip-address:1183/admin/poliv/2', 'images/water.png'], [' 1 ','http://your-home-server-ip-address:1183/noolite/switch/20', 'images/water.png'], [' 2 ','http://your-home-server-ip-address:1183/noolite/switch/21', 'images/water.png'], [' 3 ','http://your-home-server-ip-address:1183/noolite/switch/22', 'images/water.png'], [' 4 ','http://your-home-server-ip-address:1183/noolite/switch/23', 'images/water.png'], [' 5 ','http://your-home-server-ip-address:1183/admin/poliv/switch/5', 'images/water.png'], [' 6 ','http://your-home-server-ip-address:1183/admin/poliv/switch/6', 'images/water.png'], [' 7 ','http://your-home-server-ip-address:1183/admin/poliv/switch/7', 'images/water.png'], [' 8 ','http://your-home-server-ip-address:1183/admin/poliv/switch/8', 'images/water.png'], [' 9 ','http://your-home-server-ip-address:1183/admin/poliv/switch/9', 'images/water.png'], ]; var light1 = [ [' ','http://your-home-server-ip-address:1183/noolite/switch/6', 'images/light.png'], [' ','http://your-home-server-ip-address:1183/noolite/switch/0', 'images/light.png'], ['  ','http://your-home-server-ip-address:1183/noolite/switch/1', 'images/light.png'], ['  ','http://your-home-server-ip-address:1183/noolite/switch/7', 'images/light.png'], ['  ','http://your-home-server-ip-address:1183/noolite/switch/8', 'images/light.png'], [' 1 ','http://your-home-server-ip-address:1183/noolite/switch/2', 'images/light.png'], [' 1 ','http://your-home-server-ip-address:1183/noolite/switch/3', 'images/light.png'], [' 1 ','http://your-home-server-ip-address:1183/noolite/switch/4', 'images/light.png'], [' ','http://your-home-server-ip-address:1183/noolite/switch/5', 'images/light.png'], [' ','http://your-home-server-ip-address:1183/noolite/switch/9', 'images/light.png'], ]; var light2 = [ [' ','http://your-home-server-ip-address:1183/noolite/switch/15', 'images/light.png'], [' ','http://your-home-server-ip-address:1183/noolite/switch/16', 'images/light.png'], [' 2 ','http://your-home-server-ip-address:1183/noolite/switch/10', 'images/light.png'], [' 2 ','http://your-home-server-ip-address:1183/noolite/switch/11', 'images/light.png'], [' 2 ','http://your-home-server-ip-address:1183/noolite/switch/12', 'images/light.png'], [' ','http://your-home-server-ip-address:1183/noolite/switch/13', 'images/light.png'], ['  ','http://your-home-server-ip-address:1183/noolite/switch/14', 'images/light.png'], ]; var menu = new UI.Menu({ sections: [{ items: [{ title: '', subtitle: '' }] }] }); var menu1 = new UI.Menu({ sections: [{ items: [{ title: '', subtitle: '' }] }] }); var menu2 = new UI.Menu({ sections: [{ items: [{ title: '', subtitle: '' }] }] }); var menu3 = new UI.Menu({ sections: [{ items: [{ title: '', subtitle: '' }] }] }); var items = []; for (var i=0; i<noolite.length; i++) { items[i] = { title: noolite[i][0], subtitle: '', icon: noolite[i][2] }; } var items1 = []; for (var i=0; i<light1.length; i++) { items1[i] = { title: light1[i][0], subtitle: '', icon: light1[i][2] }; } var items2 = []; for (var i=0; i<light2.length; i++) { items2[i] = { title: light2[i][0], subtitle: '', icon: light2[i][2] }; } var items3 = []; for (var i=0; i<water.length; i++) { items3[i] = { title: water[i][0], subtitle: '', icon: water[i][2] }; } menu.items(0, items); menu1.items(0, items1); menu2.items(0, items2); menu3.items(0, items3); menu.show(); menu.on('select', function(e) { if (e.itemIndex == 4) { menu1.show(); } else if (e.itemIndex == 5) { menu2.show(); } else if (e.itemIndex ==8) { menu3.show(); } else { var url = noolite[e.itemIndex][1]; console.log(url); ajax({ url: url, method: 'get' }, function(data) { console.log('switched OK'); }, function(error) { // Failure! console.log('error'); } ); } }); menu1.on('select', function(e) { var url = light1[e.itemIndex][1]; console.log(url); ajax({ url: url, method: 'get' }, function(data) { console.log('switched OK'); }, function(error) { // Failure! console.log('error'); } ); }); menu2.on('select', function(e) { var url = light2[e.itemIndex][1]; console.log(url); ajax({ url: url, method: 'get' }, function(data) { console.log('switched OK'); }, function(error) { // Failure! console.log('error'); } ); }); menu3.on('select', function(e) { var url = water[e.itemIndex][1]; ajax({ url: url, method: 'get' }, function(data) { console.log('switched OK'); }, function(error) { // Failure! console.log('error'); } ); }); 


يتم كتابة الرمز وتجميعه مباشرة على موقع الويب السحابي Pebble ، ومن خلال الهاتف ، يمكن تنزيل التطبيق المجمع ، على مدار الساعة - في ثوانٍ. كل شيء بسيط للغاية بحيث يمكن لأي مهندس أتمتة شاب التعامل معه ؛)

إنه لأمر مؤسف ... إنه لأمر مؤسف أن بيبل توقف عن الوجود وفي الوقت الحالي لا أرى بديلاً. سوف بيبل تايم دائما في قلوبنا!

MQTT


في العام الماضي ، التقيت ببروتوكول رائع مثل MQTT (التاريخ: تم تطوير الإصدار الأول من البروتوكول بواسطة الدكتور أندي ستانفورد كلارك (IBM) و Arlene Nipper (Arcom) في عام 1999 وتم نشره بموجب ترخيص بدون حقوق ملكية. كانت مواصفات MQTT 3.1.1 موحدة من قبل اتحاد OASIS في عام 2014. رابط ).

هناك الكثير من المعلومات حول كيفية عمل البروتوكول وما هو العملاء ... وشعرت بخيبة أمل كبيرة لعدم وجود عملاء حقيقيين لتطبيقات الهاتف المحمول ، فقط على android.

إدراك أن عدم وجود تطبيق جيد للهاتف المحمول يمثل مشكلة كبيرة جدًا (حفرة) في مجال إنترنت الأشياء (يقول الكثير من الناس ، لكنهم لا يفعلون سوى القليل جدًا ....) - قررت أنا وفريقي في العمل إنشاء عميل لنظام Android و ios و wp بحيث تلبي جميع المعايير وتكون مريحة. سأكتب عن العميل في وقت لاحق ، بالإضافة إلى كيفية تكوين صداقات ESP8266 + MTRF64 (Noolite) وإعداد البرامج الثابتة Nodemcu. ستكون رائعة ومريحة ورخيصة وجميلة! تابع أخبار التطبيق هنا .

الصورة

يمكنك الآن التحكم في إضاءة Noolite بدون أي خوادم منزلية ومحولات USB مقابل 50-100 دولار!

مخطط عام لأتمتة المنزل


المخطط التالي لا يزال موجودًا:

المراقبة بالفيديو: المراقبة بالفيديو xeoma [ip camera]
الخادم على وحدة النظام: nginx + gunicorn + python + mqtt broker
الإدارة: ساعة بيبل + عميل MQTT
وحدات التحكم (عقد النظام): ESP8266 + optocouplers \ ds18b20، dht11 sensor [22]

نظرًا لأنني رأيت الكثير من وسائل الراحة في بروتوكول MQTT ، بدءًا من بنية الاشتراك والتواصل الفوري مع أجهزة إنترنت الأشياء النهائية ، وتنتهي بحقيقة أن رسائل MQTT يمكن أن تطير عبر جهاز التوجيه دون "إعادة توجيه" أي منافذ هناك والرقص مع الدف. ملائم! إستمتع! بحماس :)

كل هذا قادني إلى لامركزية النظام ، أي تجنب "korchvagen" واحد في المنزل والتبديل إلى العديد من العقد المسماة واستخدام وسيط MQTT السحابي (هناك وسطاء MQTT مجانًا ، على سبيل المثال: mqtt.ximxim.com (على تسجيل الدخول إلى الموقع وتمرير للوصول )) - نظرًا لأن esp8266 يحل جميع المشاكل ، ويعمل بدوره عبر wifi باستخدام بروتوكول MQTT.

بالنظر إلى أن MQTT Buddy سيوفر خدمة البرمجة النصية ، لن أفكر في كتابة أي نصوص برمجية منزلية ، سأقوم فقط بإنشائها في حل سحابي وهذا سيكون إنترنت الأشياء حقيقيًا وسيعمل! من الأقوال إلى الأفعال!

ESP8266


عندما تعرفت على لوحة التطوير هذه ، أعجبت على الفور بحقيقة أن اللوحة صغيرة ، وهناك دعم للغة برمجة LUA على البرامج الثابتة Nodemcu. ما تحتاجه هو وحدة MQTT. في الأتمتة ، تعتبر الحلول البسيطة والموثوقة هي الأساس. التكلفة من $ 2 إلى $ 5 مقابل رسوم (للنموذج الخامس على الفور مع محول USB على متن الطائرة) تسمح لك بنشر الأنظمة الفرعية بسرعة.

اتصال WiFi سريع ، والعديد من الاحتمالات. على سبيل المثال: بوابة / جراج / سقي / تحكم في الإضاءة. لدي 30 ٪ من الري في الحديقة يعمل من نظام Noolite (كتل الاتصال الجافة) ، و 70 ٪ المتبقية من لوحة تطوير esp8266 مع التحكم عبر لغة LUA باستخدام بروتوكول MQTT.

نموذج كود LUA لـ esp8266 ، والحصول على IP واستدعاء ملف العمل باستخدام MQTT
 --load credentials dofile("credentials.lua") function init(name, pass) wifi.setmode(wifi.STATION) wifi.sta.config(name, pass) wifi.sta.connect() tmr.alarm(0, 1000, 1, function() if wifi.sta.getip()== nil then print("IP unavaiable, Waiting...") else tmr.stop(0) print("Config done, IP is "..wifi.sta.getip()) print("mac : "..wifi.sta.getmac()) dofile("mqtt.lua") end end) end print("START!") init(SSID,PASSWORD) 


- ملف mqtt.lua

 local door = 7 -- gpio13 local window = 6 -- gpio12 local cooler = 5 --gpio14 local led = 4 --GPIO2 board led! LOW == turn ON local light1 = 8 --gpio 15 local light2 = 1 --gpio 5 local light3 = 2 -- gpio 4 function register_myself() m:subscribe("mqtt_buddy/#",0,function(conn) print ("subscribed to Xim mqtt.ximxim.com server") end) end m = mqtt.Client("MQTT_BUDDY_SHOW_ROOM", 120, MQTT_USER, MQTT_PASS) m:on("connect", function(client) print ("connected to Xim mqtt.ximxim.com server") end) m:on("offline", function(client) reconnect_mqtt() end) m:on("message", function(client, topic, data) --print(topic.." data:"..data) if topic == "mqtt_buddy/window" and data == "1" then print "open-close window..." gpio.write(window, gpio.HIGH) gpio.write(led, gpio.LOW) tmr.alarm(1, 1000, tmr.ALARM_SINGLE, function() gpio.write(window, gpio.LOW) gpio.write(led, gpio.HIGH) print "command to close\open window is sent!" end) elseif topic == "mqtt_buddy/door" and data == "1" then print "open-close door..." gpio.write(door, gpio.HIGH) gpio.write(led, gpio.LOW) tmr.alarm(2, 1000, tmr.ALARM_SINGLE, function() gpio.write(door, gpio.LOW) gpio.write(led, gpio.HIGH) print "command to close\open door is sent!" end) elseif topic == "mqtt_buddy/cooler" then if data == "1" then print "switch on fan..." gpio.write(cooler, gpio.HIGH) gpio.write(led, gpio.LOW) else print "switch off fan..." gpio.write(cooler, gpio.LOW) gpio.write(led, gpio.HIGH) end elseif topic == "mqtt_buddy/light1" then if data == "1" then print "switch light1 ON..." gpio.write(light1, gpio.HIGH) gpio.write(led, gpio.LOW) else print "switch light1 off..." gpio.write(light1, gpio.LOW) gpio.write(led, gpio.HIGH) end elseif topic == "mqtt_buddy/light2" then if data == "1" then print "switch light2 ON..." gpio.write(light2, gpio.HIGH) gpio.write(led, gpio.LOW) else print "switch light2 off..." gpio.write(light2, gpio.LOW) gpio.write(led, gpio.HIGH) end elseif topic == "mqtt_buddy/light3" then if data == "1" then print "switch light3 ON..." gpio.write(light3, gpio.HIGH) gpio.write(led, gpio.LOW) else print "switch light3 off..." gpio.write(light3, gpio.LOW) gpio.write(led, gpio.HIGH) end end end) m:connect(MQTT_SERVER, MQTT_SERVER_PORT, 0, function(conn) register_myself() end) 


المشكلة


بالانتقال إلى مجتمع ضخم من المفكرين ، أردت أن أتطرق إلى موضوع بالغ الأهمية ، أو بالأحرى المشكلة التي أريد حلها ، ولكن ليس هناك وقت كافٍ لمزيد من البحث / المعرفة المتعمقة.

خلاصة القول: مع اللامركزية ، تبقى المراقبة بالفيديو ، والتي تتطلب بطريقة أو بأخرى جهاز مضيف (الحد الأدنى) لنقل صور المصدر إما إلى خادم مراقبة فيديو (مثل ivideon) أو حتى معالجة الفيديو على جهاز منزلي ، مثل xeoma (على الرغم من أن لديهم أيضًا سحابة) - بطريقة أو بأخرى - أنت بحاجة إلى "تدفقات فيديو" إلى الأمام ، صور لقوة الحوسبة النهائية (حلول السحابة) - أو العكس - لجعل البث بسيطًا.

هناك أفكار بشأن تلقي صور المصدر من الكاميرا (هناك أيضًا مشكلة هنا ، ليس لكل كاميرا عنوان URL لاستلام صورة من الكاميرا ومن غير الواضح بشكل عام كيف سيتعرف الآخرون على عنوان URL هذا ....) وإعادة توجيهه إلى قناة MQTT حيث يتم دعم البيانات الثنائية (التي هناك صورة يمكن إرسالها بسهولة عبر بروتوكول mqtt في شكل ثنائي).

ربما حاول شخص ما بالفعل تنفيذ مثل هذه الأشياء = ESP8266 + كاميرا ويب IP؟
الرجاء الرد (bogdanovich.alex [@] gmail.com). سأكون ممتنا للغاية!

عند تنفيذ probros ، سيختفي سؤال الخادم المنزلي. لماذا؟ لأنه يأكل الكهرباء ويسخن فرني :)

الصورة

كل يوم إيجابي ومزاج جيد!

Source: https://habr.com/ru/post/ar403273/


All Articles