
इस प्रकार, मैंने प्रबंधित सॉफ़्टवेयर सामान की एक प्रणाली की संरचना का वर्णन किया।
सरलीकृत मॉडल में मुख्य प्रक्रिया ( bobaoskit.worker
) और गौण स्क्रिप्ट ( bobaoskit.sdk
और bobaoskit.accessory
का उपयोग करके) शामिल हैं। मुख्य प्रक्रिया से कुछ क्षेत्रों को नियंत्रित करने के लिए एक गौण के लिए अनुरोध है। गौण से, बदले में, स्थिति को अद्यतन करने के लिए मुख्य बात का अनुरोध है।
उदाहरण के रूप में एक साधारण रिले लें।
एक आने वाली कमांड के साथ, रिले कभी-कभी विभिन्न कारणों (उपकरण फ्रीज, आदि) के कारण अपनी स्थिति नहीं बदल सकता है। इसके अनुसार, हम टीमों को कितना नहीं भेजेंगे, स्थिति नहीं बदलेगी। और, एक अन्य स्थिति में, तृतीय-पक्ष प्रणाली द्वारा कमांड किए जाने पर रिले अपना राज्य बदल सकता है। इस स्थिति में, इसकी स्थिति बदल जाएगी, एक्सेसरी स्क्रिप्ट स्थिति परिवर्तन के बारे में आने वाली घटना का जवाब दे सकती है और मुख्य प्रक्रिया के लिए अनुरोध भेज सकती है।
प्रेरणा
कई वस्तुओं पर Apple होमकिट लागू करने के बाद, मैंने एंड्रॉइड के समान कुछ ढूंढना शुरू कर दिया, क्योंकि मेरे पास केवल आईओएस उपकरणों से काम करने वाला आईपैड है। मुख्य मानदंड एक स्थानीय नेटवर्क पर काम करने की क्षमता थी, बिना क्लाउड सेवाओं के। इसके अलावा, होमकिट में क्या गायब था, इसकी सीमित जानकारी थी। उदाहरण के लिए, आप थर्मोस्टैट ले सकते हैं। इसका सारा नियंत्रण ऑपरेटिंग मोड (ऑफ, हीटिंग, कूलिंग और ऑटो) और सेट तापमान की पसंद तक कम हो जाता है। सरल बेहतर है, लेकिन, मेरी राय में, हमेशा नहीं। पर्याप्त नैदानिक जानकारी नहीं। उदाहरण के लिए, क्या एयर कंडीशनर, convector, क्या वेंटिलेशन पैरामीटर काम कर रहे हैं। आंतरिक त्रुटि के कारण शायद एयर कंडीशनर काम नहीं कर सकता है। यह देखते हुए कि इस जानकारी पर विचार किया जा सकता है, इसके कार्यान्वयन को लिखने का निर्णय लिया गया।
कोई व्यक्ति ioBroker, OpenHAB, होम-असिस्टेंट जैसे विकल्पों को देख सकता है।
लेकिन उन सूचीबद्ध लोगों के नोड.जेएस पर, केवल ioBroker (जब मैं एक लेख लिख रहा हूं, तो ध्यान दिया कि रेडिस भी प्रक्रिया में शामिल है)। और उस समय तक, उन्होंने पता लगाया था कि इंटरप्रोसेस संचार को कैसे व्यवस्थित किया जाए, और रेडिस से निपटने के लिए दिलचस्प था, जिसे हाल ही में सुना गया है।
आप निम्नलिखित विनिर्देश पर भी ध्यान दे सकते हैं:
→ वेब थिंग एपीआई
युक्ति

Redis
इंटरप्रोसेस संचार में मदद करता है, और सामान के लिए डेटाबेस के रूप में भी कार्य करता है।
bobaoskit.worker
मॉड्यूल अनुरोध कतार ( bee-queue
का उपयोग करते हुए redis
शीर्ष पर) होता है, डेटाबेस से अनुरोध / लिखता है, निष्पादित करता है।
उपयोगकर्ता स्क्रिप्ट में, bobaoskit.accessory
ऑब्जेक्ट इस विशेष एक्सेसरी के लिए एक अलग bee-queue
लिए सुनता है, निर्धारित क्रिया करता है, bobaoskit.sdk
ऑब्जेक्ट के माध्यम से मुख्य प्रक्रिया कतार में अनुरोध भेजता है।
प्रोटोकॉल
सभी अनुरोध और प्रकाशित संदेश JSON
प्रारूप में तार हैं, method
और payload
फ़ील्ड शामिल हैं। payload = null
भी फ़ील्ड की आवश्यकता होती है।
bobaoskit.worker
लिए अनुरोध:
- विधि:
ping
, पेलोड: null
। - विधि:
get general info
, पेलोड: null
- विधि:
clear accessories
, पेलोड: null
, - विधि:
add accessory
,
पेलोड:
{ id: "accessoryId", type: "switch/sensor/etc", name: "Accessory Display Name", control: [<array of control fields>], status: [<array of status fields>] }
- विधि:
remove accessory
, पेलोड को remove accessory
: accessoryId/[acc1id, acc2id, ...]
- विधि:
get accessory info
, पेलोड: null/accId/[acc1id, acc2id...]
payload
फ़ील्ड में, आप एक्सेसरी / मास id
की null
/ id
भेज सकते हैं। यदि null
भेजा जाता है, तो सभी मौजूदा सामानों के बारे में जानकारी वापस आ जाएगी। - विधि:
get status value
, पेलोड: {id: accessoryId, status: fieldId}
payload
फ़ील्ड में आप फॉर्म {id: accessoryId, status: fieldId}
, (जहाँ पर status
फ़ील्ड फ़ील्ड का एक सरणी हो सकता है) का ऑब्जेक्ट भेज सकते हैं, या payload
इस तरह की वस्तुओं का एक सरणी हो सकता है। - विधि:
update status value
, पेलोड: {id: accessoryId, status: {field: fieldId, value: value}
payload
फ़ील्ड में, आप फॉर्म {id: accessoryId, status: {field: fieldId, value: value}}
, का एक ऑब्जेक्ट भेज सकते हैं, (जहां status
फ़ील्ड एक सरणी हो सकती है {field: fieldId, value: value}
, या payload
ऐसी वस्तुओं की एक सरणी हो सकती है) की तरह। - विधि:
control accessory value
, पेलोड को control accessory value
: {id: accessoryId, control: {field: fieldId, value: value}}
।
payload
फ़ील्ड में, आप फॉर्म {id: accessoryId, control: {field: fieldId, value: value}}
का ऑब्जेक्ट भेज सकते हैं, (जहाँ control
फ़ील्ड एक ऐरे हो सकता है {field: fieldId, value: value}
, या payload
ऐसी वस्तुओं की एक सरणी हो सकती है की तरह।
किसी भी अनुरोध के जवाब में, यदि सफल हो, तो फॉर्म का एक संदेश:
{ method: "success", payload: <...> }
विफलता के मामले में:
{ method: "error", payload: "Error description" }
संदेश निम्नलिखित मामलों में redis PUB/SUB
चैनल ( config.json
में परिभाषित) में भी प्रकाशित किए जाते हैं: सभी सामान साफ़ किए जाते हैं ( clear accessories
); गौण जोड़ा ( add accessory
); गौण हटा (गौण हटा); गौण अद्यतन स्थिति ( update status value
)।
प्रसारण संदेशों में दो फ़ील्ड भी शामिल हैं: method
और payload
।
ग्राहक SDK
विवरण
क्लाइंट SDK ( bobaoskit.accessory
) आपको js
स्क्रिप्ट से उपरोक्त विधियों को कॉल करने की अनुमति देता है।
मॉड्यूल के अंदर दो कंस्ट्रक्टर ऑब्जेक्ट हैं। पहला उपरोक्त विधियों तक पहुँचने के लिए एक Sdk
ऑब्जेक्ट बनाता है, और दूसरा इन कार्यों के शीर्ष पर एक गौण - एक आवरण बनाता है।
const BobaosKit = require("bobaoskit.accessory"); // sdk. // , // , // sdk, const sdk = BobaosKit.Sdk({ redis: redisClient // optional job_channel: "bobaoskit_job", // optional. default: bobaoskit_job broadcast_channel: "bobaoskit_bcast" // optional. default: bobaoskit_bcast }); // const dummySwitchAcc = BobaosKit.Accessory({ id: "dummySwitch", // required name: "Dummy Switch", // required type: "switch", // required control: ["state"], // requried. , . status: ["state"], // required. . sdk: sdk, // optional. // , sdk // redis: undefined, job_channel: "bobaoskit_job", broadcast_channel: "bobaoskit_bcast" });
एसडीके ऑब्जेक्ट Promise
तरीकों का समर्थन Promise
है:
sdk.ping(); sdk.getGeneralInfo(); sdk.clearAccessories(); sdk.addAccessory(payload); sdk.removeAccessory(payload); sdk.getAccessoryInfo(payload); sdk.getStatusValue(payload); sdk.updateStatusValue(payload); sdk.controlAccessoryValue(payload);
BobaosKit.Accessory({..})
ऑब्जेक्ट BobaosKit.Accessory({..})
BobaosKit.Sdk(...)
ऑब्जेक्ट के शीर्ष पर एक आवरण है।
अगला, मैं दिखाऊंगा कि यह कैसे घूमता है:
// self.getAccessoryInfo = _ => { return _sdk.getAccessoryInfo(id); }; self.getStatusValue = payload => { return _sdk.getStatusValue({ id: id, status: payload }); }; self.updateStatusValue = payload => { return _sdk.updateStatusValue({ id: id, status: payload }); };
दोनों ऑब्जेक्ट भी EventEmitter
।
Sdk
ready
और broadcasted event
घटनाओं पर कार्य broadcasted event
है।
Accessory
घटनाओं के लिए ready
कार्यों, error
, control accessory value
पर कार्य करता है।
उदाहरण
const BobaosKit = require("bobaoskit.accessory"); const Bobaos = require("bobaos.sub"); // init bobaos with default params const bobaos = Bobaos(); // init sdk with default params const accessorySdk = BobaosKit.Sdk(); const SwitchAccessory = params => { let { id, name, controlDatapoint, stateDatapoint } = params; // init accessory const swAcc = BobaosKit.Accessory({ id: id, name: name, type: "switch", control: ["state"], status: ["state"], sdk: accessorySdk }); // state // KNX bobaos swAcc.on("control accessory value", async (payload, cb) => { const processOneAccessoryValue = async payload => { let { field, value } = payload; if (field === "state") { await bobaos.setValue({ id: controlDatapoint, value: value }); } }; if (Array.isArray(payload)) { await Promise.all(payload.map(processOneAccessoryValue)); return; } await processOneAccessoryValue(payload); }); const processOneBaosValue = async payload => { let { id, value } = payload; if (id === stateDatapoint) { await swAcc.updateStatusValue({ field: "state", value: value }); } }; // KNX // state bobaos.on("datapoint value", payload => { if (Array.isArray(payload)) { return payload.forEach(processOneBaosValue); } return processOneBaosValue(payload); }); return swAcc; }; const switches = [ { id: "sw651", name: "", controlDatapoint: 651, stateDatapoint: 652 }, { id: "sw653", name: " 1", controlDatapoint: 653, stateDatapoint: 653 }, { id: "sw655", name: " 2", controlDatapoint: 655, stateDatapoint: 656 }, { id: "sw657", name: " 1", controlDatapoint: 657, stateDatapoint: 658 }, { id: "sw659", name: "", controlDatapoint: 659, stateDatapoint: 660 } ]; switches.forEach(SwitchAccessory);
WebSocket एपीआई
bobaoskit.worker
./config.json
में परिभाषित WebSocket पोर्ट पर सुनता है।
इनकमिंग अनुरोध JSON
स्ट्रिंग्स हैं जिनमें निम्नलिखित फ़ील्ड होनी चाहिए: request_id
, method
और payload
।
एपीआई निम्नलिखित अनुरोधों तक सीमित है:
- विधि:
ping
, पेलोड: null
- विधि:
get general info
, पेलोड: null
, - विधि:
get accessory info
, पेलोड: null/accId/[acc1Id, ...]
- विधि:
get status value
, पेलोड: {id: accId, status: field1/[field1, ...]}/[{id: ...}...]
- विधि:
control accessory value
, पेलोड: {id: accId, control: {field: field1, value: value}/[{field: .. value: ..}]}/[{id: ...}, ...]
get status value
, control accessory value
विधियाँ payload
फ़ील्ड को एक ऑब्जेक्ट या एक सरणी के रूप में स्वीकार करती हैं। payload
अंदर control/status
क्षेत्र या तो एकल ऑब्जेक्ट या एक सरणी हो सकते हैं।
सर्वर से निम्नलिखित घटना संदेश भी सभी ग्राहकों को भेजे जाते हैं:
- विधि:
clear accessories
, पेलोड: अशक्त - विधि:
remove accessory
, पेलोड remove accessory
: एक्सेसरी आईडी - विधि:
add accessory, payload
: {आईडी: ...} - विधि:
update status value, payload
: {आईडी: ...}
dnssd
स्थानीय नेटवर्क पर _bobaoskit._tcp
पोर्ट को अनुप्रयोग _bobaoskit._tcp
सेवा के रूप में _bobaoskit._tcp
करता है, dnssd
मॉड्यूल के लिए धन्यवाद।
डेमो
एक अलग लेख लिखा जाएगा कि कैसे आवेदन वीडियो के साथ लिखा गया था और flutter
इंप्रेशन।
अंतभाषण
इस प्रकार, सॉफ्टवेयर सामान के प्रबंधन के लिए एक सरल प्रणाली प्राप्त की गई थी।
सहायक उपकरण वास्तविक दुनिया से वस्तुओं के विपरीत हो सकते हैं: बटन, सेंसर, स्विच, थर्मोस्टैट, रेडियो। चूंकि कोई मानकीकरण नहीं है, आप control < == > update
में फिट होने वाले किसी भी सामान को लागू कर सकते हैं control < == > update
मॉडल।
क्या बेहतर किया जा सकता है:
- एक बाइनरी प्रोटोकॉल कम डेटा भेजने की अनुमति देगा। दूसरी ओर,
JSON
, विकास और समझने के लिए तेज़ है। बाइनरी प्रोटोकॉल को भी मानकीकरण की आवश्यकता है।
बस इतना ही, मुझे किसी भी प्रतिक्रिया की खुशी होगी।