يسعى هذا المشروع إلى إجراء اختبار صغير لتكنولوجيا نقل Lora لجمع المعلومات التي يمكن استخدامها من قبل CTIT Foundation. سيتم إرسال المعلومات من جهاز نهائي (عقدة أو عميل) ، وسيتم جمع هذه المعلومات بواسطة جهاز بوابة ، وهذا بدوره سيقوم بإعادة توجيهه إلى خادم لتخزينه.
Lora هي تقنية لاسلكية (مثل WiFi أو Bluetooth أو LTE أو Sigfox أو Zigbee) التي تستخدم نوعًا من تعديل تردد الراديو بواسطة Semtech.
تدار هذه التكنولوجيا حاليًا من قبل التحالف Lora الذي يشهد على جميع تصنيع الأجهزة التي تسعى إلى العمل مع هذه التكنولوجيا.
لدى Lora تسامحًا كبيرًا مع التداخل ، وحساسية عالية لتلقي البيانات (-168 ديسيبل) ، والاستهلاك المنخفض للغاية (يمكن أن يستمر الجهاز لمدة عقد مع بطارية واحدة) ومدى من 10 إلى 20 كم (اعتمادًا على ما إذا كانت الرؤية المباشرة أو طوبولوجيا الأرض متاحة). من ناحية أخرى ، نجد نقل بيانات منخفض للغاية (حتى 255 بايت).
كل هذا يجعل تقنية النقل هذه مفيدة لمسافات كبيرة أو شبكات إنترنت الأشياء التي لا تحتاج أو لا يمكنها الوصول إلى التيار الكهربائي.
تعمل Lora على ترددات مجانية (هذه هي 868 ميجا هرتز في أوروبا ، 916 ميجا هرتز في أمريكا أو 433 ميجا هرتز في آسيا ، على سبيل المثال) والتي ، والتي ، ، تجمع غير مُزعم لتوفير مورد لشبكة كهربائية ومزود بسلاسة بالاتصالات (نستخدم التردد الراديوي) ، يجعل من الممكن أن يرسل المعلومات دون خطر.
يمكننا التواصل مع الأجهزة من خلال Loremac (المعروف أيضًا من خلال Lora) أو بواسطة Lorawan.
لوراماك : يستخدم لتوصيل جهازين مع بعضهما البعض مع نقطة إلى نقطة ، يرسل أحدهم المعلومات وآخر يجمعها (أو العكس).
لوروان : تستخدم لتوصيل شبكة من الأجهزة. في هذا النهج ، يظهر رقم البوابة (الجهاز الذي يجمع معلومات جهاز واحد أو أكثر ويقوم بإعادة توجيهه إلى الخادم). في لوروان ، يجب ترشيح المعلومات لمعرفة الأجهزة التي يجب أن تستمع إلى البوابة وأيها تتجاهلها ، ولكن سيتم رؤيتها لاحقًا. يستخدم هذا النهج طوبولوجيا النجوم.
من ناحية أخرى ، في لوروان ، هناك أيضًا ثلاثة أنواع من الأجهزة أو العقد النهائية :
*في الأمثلة ، الدعم فقط لعقد الفئة A و B (تدعمها المكتبة المستخدمة) ، ولكن يتم تنفيذ النوع A. فقط
إذا تم استخدام نطاق التردد المجاني في أوروبا (868 ميجا هرتز) ، فيجب أخذ بعض القيود في الاعتبار:
في كل نطاق تردد ، توجد العديد من القنوات أو النطاقات الفرعية ، في حالة الأوروبيين (868 ميجا هرتز) ، نجد 10 قنوات مرقمة من 0 إلى 9 ، ولكن ، على سبيل المثال في أمريكان (915 ميجا هرتز) يمكننا العثور على ما يصل إلى 64.
إن إرسال المعلومات من خلال قناة أو أخرى هو مهمة تسهل المكتبات عادةً استخدامها.
في بعض الأطباق النهائية ، من الممكن تعديل Datarrate أو spreacher الجهاز.
يرتبط Datarrate و expertingFactor: يشير داتر من 0 إلى SF12 ويشير داتر من 5 إلى SF7. كل ذلك على تردد 125 كيلو هرتز وجود استثناء التالي: تشير مياه بيانات 6 إلى SF7 مع 250 كيلو هرتز.
جهازان (أحدهما للعقدة والآخر للبوابة ، والتي يجب أن تحتوي أيضًا على اتصال WiFi) وحساب مرتبط في TTS ( شبكة الأشياء ) أو chirpstack (القدرة على استخدام الخادم الخاص به في المنزل). في هذا المثال ، أمثلة Loremac و Lorawan التي تستخدم عقدة Arduino وبوابة Pycom.
للبدء ، يكفي استنساخ المستودع:
git clone https://github.com/Javieral95/Getting_Started_With_LoRa.git
ثم قم بتحميل المشاريع ذات الصلة على الأجهزة
لماذا اثنين من IDES؟ امتداد Pymakr بسيط ، بالكاد يعمل في رمز Visual Studio. لا تتردد في استخدام مساحة العمل الأكثر راحة.
كلا الجهازين لهما أنتيرا لورا متصلة بهم.
ملاحظة : رمز Arduinomkr1300 (أكثر استعدادًا للاستخدام مثل جهاز Lora End-Device) والرموز لاستخدام pysense أو pytrack حيث يتم تضمين End-evex أيضًا في repos.

مثال Loramac (تم العثور عليه في مجلد Homeon) هو وظيفي الاستفادة من جهاز Arduino النهائي وبوابة Pycom.
ترسل العقدة فقط معلومات الرمز المتشددين وتتصل البوابة فقط بـ Lora و WiFi ، وتتلقى معلومات Pycom وتطبع قراءة البيانات (على الرغم من أنها نفذت وظيفة إرسال البيانات إلى الشبكة).
يتم الاستغناء عن استخدام خادم الشبكة.
لمعرفة المزيد ، يمكنك الوصول إلى المجلد /loramac .
لاستخدام هذه الأمثلة (والتي يتم استخدامها الوظيفية باستخدام جهاز نهائي Arduino وبوابة Pycom) ، يلزم خادم لتصور البيانات. في هذا المثال ، تمت معالجة استخدام شبكة الأشياء و chirpstack (المعروف سابقًا باسم Loraserver).
لمعرفة المزيد ، يمكنك الوصول إلى المجلد /لوروان ثم متابعة استشارة هذه الوثائق.
هناك نوعان من المصادقة في لوروان:
*في الأمثلة في الوقت الحالي يتم صنع OTAA فقط.
كما ذكرنا سابقًا ، سنحتاج إلى خادم. في هذا المثال ، تم استخدام إصدار مجاني من شبكة الأشياء وخادم ChirpStack المملوك لـ Pycom وآخر تم نشره في المنزل.
إنه البديل الأكثر موثوقية وآمنة وأفضل موثقة. ومع ذلك ، يشير كل شيء إلى أنه سيتوقف عن فتحه (هناك حد 50 عقدة لكل تطبيق).
إنشاء تطبيق بسيط ، والوصول إلى القائمة وانقر فوق الزر +. بمجرد أن نشير إلى اسم التطبيق ، معرف فريد ووصف.
عند إنشاء التطبيق ، يمكننا إضافة الأجهزة النهائية (العقد) النقر فوق الزر +.
البوابات هي أجهزة مسؤولة عن إرسال حركة المرور التي تأتي من العديد من الأجهزة النهائية (تنتمي إلى عدة تطبيقات) وترحيل إلى الخادم. يعد إنشاء بوابة بسيطًا أيضًا ، ثم انقر على الزر + وملء النموذج مع الاهتمام بالمفاهيم التالية:
لتكون قادرًا على قراءة البيانات التي أرسلتها العقدة إلى الخادم ، من الضروري فك تشفير الحمولة النافعة ، في حالة TTN ، سنقوم بذلك لكل جهاز ، في علامة التبويب Formload Formatters . نختار كيف تكتب خيار JavaScript و:
function Decoder(bytes, port) {
// Decode plain text; for testing only
return {
myTestValue: String.fromCharCode.apply(null, bytes)
};
}
arduino_ttn_decoder.js لقد ثبت أن جميع العناوين السداسية في شبكة الأشياء موجودة في العمدة ، فليس من المهم عند برمجة الأجهزة ولكن الأخطاء عانت في الإصدارات السابقة.
هذا هو البديل المفتوح المصدر ، لا يزال قيد التطوير وتوثيقه ليس جيدًا. ومع ذلك ، فإنه يعمل ويسمح لبدء الخادم.
يوفر Pycom خادم ChirpStack لتوصيل جهاز Gateway الخاص بك.
يشبه التطبيق التفصيلي في قسم شبكة الأشياء.
يجب أن تنتقل إلى الجهاز الرصيف لقسم الخادم ، بمجرد الوصول إلى ملف التعريف الذي اهتمامات (OTAA في هذه الحالة) وتعديل الإصدارات:
لإنشاء بوابة ، قم بالوصول إلى نفس الاسم وانقر فوق الزر +. املأ النموذج الذي يولي اهتمامًا خاصًا لحقل معرف البوابة (64 بت في سداسي عشري يحدد البوابة) ، يمكنك جعل chirpstack يولدها لك ولكن عادة ما يتم استخدام جهاز Mac للجهاز (إذا كنت لا تعرفه في القسم الذي يفسر Pycom ، فسيتم تفصيله على أنه الحصول عليه).
يمكنك ترك بقية القيم الافتراضية.
من أجل قراءة البيانات التي أرسلتها العقدة إلى الخادم ، من الضروري فك تشفير الحمولة ، في حالة ChirpStack ، سنفعل ذلك لكل ملف تعريف للجهاز ، في الجهاز Propiles_ نصل إلى ملف التعريف الذي يثير اهتمامنا (في هذه الحالة OTAA) ونحن نصل إلى علامة التبويب برامج الترميز :
نختار في وظائف برنامج ترميز DECIPT المخصص و:
function Decode(fPort, bytes) {
var tempObj = new Object();
tempObj.data=bytes;
tempObj.decodedData = String.fromCharCode.apply(null, bytes);
tempObj.message = "Informacion recibida del nodo";
return tempObj;
}
arduino_chirpstark_decoder.js لقد أثبت أن جميع عناوين chirpstack سداسية عشرية في minuscules ، فهي ليست مهمة عند برمجة الأجهزة ولكن الأخطاء عانت في الإصدارات السابقة.
يوفر ChirpStack بديلاً لـ OpenSource لإطلاق الخادم الخاص بنا في Lorawan ، ويسمح لنا بالقيام بذلك بطريقة بسيطة ومن خلال الحاويات.
هذا هو السبب في أن مستودعًا آخر يملكه مؤسس Chirpstack (Brocar) يسمح لهذه العملية: تم استنساخ Chirpstack-Docker في المستودع الحالي. نجدها في مجلد chirpstack-docker .
لدى Chirpstack مكونات مختلفة في بنيةها لجعل الخدمة قادرة على التشغيل ، فهي التالية:

تتيح لنا طريقة عرض الخادم في شكل حاويات تجريد الكثير من مكونات الهندسة المعمارية ، ومع ذلك فهي مفصلة أدناه:
قبل النشر ، يجب تكوين جميع المعلمات اللازمة في ملفات التكوين المخزنة في لوحة التكوين .
يمكنك استشارة الوثائق الرسمية التالية:
ملاحظة: تكون ملفات التكوين حساسة للمساحات الفارغة أو الخطوط الفارغة (تم العثور عليها في شبكة البعوض) ، تحقق من الملفات والإلغاء لتجنب الأخطاء.
كما ذكرنا سابقًا ، فإن النشر في الحاويات بسيط ويقع في دليل chirpstack-docker .
بمجرد تكوين ما هو ضروري بالفعل ، يكفي وضعها في دليل وإطلاق chirpstack-docker :
docker-compose up
مع التكوين الافتراضي ، يمكنك الوصول إلى الخادم في الاتجاه المحلي: 8080 . سيكون المستخدم هو المسؤول وكلمة مرور المسؤول .
لنبدأ في إضافة التكوين الأساسي:
بمجرد تكوين الخادم ، سيتعين علينا تسجيل بواباتنا وإنشاء تطبيقات لتسجيل أجهزتنا النهائية. يتم تنفيذ هذه العملية بشكل مشابه للذات الموضح في القسم السابق من هذا الوثائق: ChirpStack (Lora Server).
بالإضافة إلى ذلك ، يجب الإشارة إلى الوظيفة التي تدلل وتشفير المعلومات المستلمة ، كما يتم شرحها في القسم السابق.
الرمز المستخدم لإطلاق البوابة مفصلة أدناه في pycom (fipy مع pytrack). يقع هذا الرمز في Lorawan/LorapyComgateway .
تم استخدام مكتبة Nanogateway PY التي تسمح بإطلاق البوابة في دقائق.
يقوم Nano-Gateway بتحويل جهاز Pycom إلى بوابة بسيطة تستمع فقط إلى قناة نطاق التردد (أحادي اللون) ، للاستماع إلى المزيد من النطاقات في Pycom ، من الممكن أن يكون من الضروري لبوابة تجارية.
في ملف التكوين ، كل ما هو ضروري لتخصيص البوابة:
WIFI_MAC = ubinascii.hexlify(machine.unique_id()) #.toUpper() para TTS
SERVER = 'loraserver.pycom.io' #(or url of your server)
GATEWAY_ID = WIFI_MAC[:6] + "ffff" + WIFI_MAC[6:12] #Minusculas: Chirpstack
NTP = "es.pool.ntp.org"
NTP_PERIOD_S = 3600
#WiFi settings (change it)
WLAN_SSID = "MyAwesomeWiFi" #"pycom-wifi"
WLAN_PASS = "CheckOutThisGoodPassword" #"securepassword"
WLAN_TIMEOUT_MS = 180000
### LoRaWAN for EU868 ###
LORA_FREQUENCY = 868500000
#Spreading Factor: (Higher value in SF=More distance but less speed transmision)
LORA_GW_DR = "SF7BW125" # DR_5,Can change in range: SF7 to SF15 (SF7B250 also exists)
LORA_NODE_DR = 5 #5 (6 uses 250Khz) for SF7, 4 for SF6.. all using 125Khz
###
def get_gateway_id():
print("Your gateway_id is: {}".format(GATEWAY_ID)) #The gateway is b'THIS_STRING'
return GATEWAY_ID
ملاحظة: إذا قمت بتوصيل بوابةك بشبكة محلية بدون اتصال بالإنترنت ، فسيقوم بإرجاع خطأ عند مزامنة الساعات. يمكنك الخروج من الخطوة التي تعلق على الأسطر التالية من الكود في وظيفة START (الذاتية) لملف nanogateway.py كما يوضح المثال التالي:
# get a time sync
self._log('Syncing time with {} ...', self.ntp_server)
#self.rtc.ntp_sync(self.ntp_server, update_period=self.ntp_period)
#while not self.rtc.synced():
# utime.sleep_ms(50)
self._log("RTC NTP sync complete")
لا يتم استخدام العديد من وظائف الملفات الرئيسية ، فمن الضروري فقط تشغيل البوابة على النحو التالي وسيعمل بالفعل.
def init_loraWAN_gateway():
print("Initializing LoRaWAN nano Gateway")
nanogw = NanoGateway(
id=config.GATEWAY_ID,
frequency=config.LORA_FREQUENCY,
datarate=config.LORA_GW_DR,
ssid=config.WLAN_SSID,
password=config.WLAN_PASS,
server=config.SERVER,
port=config.PORT,
ntp_server=config.NTP,
ntp_period=config.NTP_PERIOD_S
)
print("Ok! Now you have a LoRaWAN Gateway! Lets start it, wait . . .")
pycom.rgbled(0xAA0000)
nanogw.start()
nanogw._log('. . . Yeah! Nano gateway is connected and running, enjoy the log:')
pycom.rgbled(0x000000)
سيحتفظ Pycom بالضوء الأحمر حتى يتمكن من الاتصال ، بمجرد أن يستمع إلى أجهزة الأجهزة سوف تومض LED الأخضر.
تم تفصيل ما يلي لتشغيل عقدة الفصل A باستخدام Arduino.
تستخدم النظرية جميع القنوات المتوفرة في نطاق التردد ، وفي وقت لاحق ، سيتم رؤية طريقة للقوة واحدة فقط (غير موصى بها).
تم استخدام مكتبة McCi Arduino Lorawan التي تتيح لك تجريد العديد من جوانب اتصال Lora. تم تثبيته بواسطة مدير مكتبة Platformio.
بشكل أساسي الرمز المستخدم لعميل Arduino هو الرمز الموجود في مثال ttn-otaa.ino على المكتبة ، باستثناء بعض التعديل.
يتم تكوين التكوين في ملفين مختلفين:
يشار إلى جميع التكوينات المتعلقة بـ Lorawan ، كما هو موضح أعلاه في ملف LoRawan.CPP . في بداية المستند ، من المفترض أن يتم الإشارة إلى البيانات: app_eui و dev_eui و app_key (العين إلى التنسيق الموضح أدناه).
ثم المثال في chirpstack:
static const u1_t PROGMEM APPEUI[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const u1_t PROGMEM DEVEUI[8] = {0x7b, 0x6b, 0xff, 0x2c, 0x7b, 0x2c, 0x19, 0x5a};
static const u1_t PROGMEM APPKEY[16] = {0xbd, 0x21, 0x5a, 0x82, 0xb2, 0xf7, 0x92, 0xf3, 0xc7, 0xcb, 0xb2, 0x88, 0xc7, 0x55, 0x33, 0xe7};
ضمن تكوين المفتاح بأكمله ، في ملف loraWan.cpp ، يمكننا اختيار ما إذا كان سيتم إرسال نص مسطح أو بيانات من مستشعر درجة الحرارة والرطوبة. ينقذ الخيار المطلوب:
/******* Send data config *******/
// Use this to send a Hello world in plain text
// static uint8_t mydata[] = "Hello World!";
// Use this to send sensor data
const int neededBytes = 4; // 4 bytes: 2 for temperature and 2 for humidity, can change this value
static byte mydata[neededBytes];
static LoraEncoder encoder(mydata);
اعتمادًا على المعلومات المرسلة ، يجب استخدام فك التشفير أو وظيفة أخرى ، كما هو موضح في أقسام شبكة الأشياء و chirpstack.
كما رأينا سابقًا ، فإن لوحة Nano-Gateway Pycom قادرة فقط على القراءة على قناة بينما يكون جهاز Arduino النهائي قادرًا على البث على جميع قنوات النطاق (على سبيل المثال ، في النطاق الأوروبي هناك 10 قنوات). على الرغم من أنه لا ينصح به (قد يتم اختراق قاعدة 1 ٪) يمكن إجبارها على استخدام قناة فقط وتردد فقط بسبب مشكلات التطوير والاختبار.
لهذا ، من الضروري تعديل رمز المكتبة ، وبشكل أكثر تحديداً lorabase_eu868.h
enum {
EU868_F1 = 868500000, // g1 SF7-12
EU868_F2 = 868500000, // g1 SF7-12 FSK SF7/250
EU868_F3 = 868500000, // g1 SF7-12
EU868_F4 = 868500000, // g2 SF7-12
EU868_F5 = 868500000, // g2 SF7-12
EU868_F6 = 868500000, // g3 SF7-12
EU868_J4 = 868500000, // g2 SF7-12 used during join
EU868_J5 = 868500000, // g2 SF7-12 ditto
EU868_J6 = 868500000, // g2 SF7-12 ditto
};
enum {
EU868_FREQ_MIN = 868500000,
EU868_FREQ_MAX = 868500000
};
يجب أيضًا استدعاء الوظيفة التالية في بداية وظيفة Lora ( LoRawan_StartJob () :
// Define the single channel and data rate (SF) to use
void disableChannels(int selectedChannel, int dr)
{
// Disable all channels, except for the one defined above.
// ONLY FOR TESTING AND DEVELOPING!
for (int i = 0; i < 9; i++)
{ // For EU; for US use i<71
if (i != selectedChannel)
{
LMIC_disableChannel(i);
}
}
// Set data rate (SF) and transmit power for uplink
LMIC_setDrTxpow(dr, 14);
}
توجد القناة والمواد المراد تكوينها في بداية الملف ، في الأسطر (افتراضيًا: القناة 0 و DATATE المطلوب لعامل الانتشار 7 الذي تكون قيمته 5):
/******* Channel config (only change if you want to uses a single channel) *******/
const int channel = 0; // Use if you want to use only one Band's Channel.
const int dr = DR_SF7; // Use if you want to use a specific datarate (The spreading factor mark the dr's value).
هذا من شأنه أن يجعل فقدان الحزم بشكل كبير ، على الرغم من أنه لا يزال هناك بعض لا تتلقى البوابة.
فقط انسخ المشروع إلى لوحة Arduino الخاصة بك.
تعمل المكتبة من الأحداث ، في هذه الحالة ، ستكون المصادقة الأكثر أهمية (عند اكتمالها سترى المفاتيح في وحدة التحكم) وشحن البيانات.
سيكون الحدث الذي يتم إرسال البيانات فيه EV_TXCOMPLETE في وظيفة ONEVENT VOID (EV_T EV) لملف lorawan.cpp ، يلاحظ أن الحدث يتضمن "نافذة RX" ، في الوقت الذي يستمع فيه الجهاز.
case EV_TXCOMPLETE:
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
if (LMIC.txrxFlags & TXRX_ACK)
Serial.println(F("Received ack"));
if (LMIC.dataLen)
{
Serial.print(F("Received "));
Serial.print(LMIC.dataLen);
Serial.println(F(" bytes of payload"));
}
// Schedule next transmission
os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
break;
الوظيفة ، في نفس الملف ، حيث سيتم تفصيل البيانات التي يتم إرسالها هي do_send (التعليق أو الشروط الخطوط التي تشفر المعلومات إذا كنت ترغب في إرسال نص مسطح):
void do_send(osjob_t *j)
{
// Check if there is not a current TX/RX job running
if (LMIC.opmode & OP_TXRXPEND)
{
Serial.println(F("OP_TXRXPEND, not sending"));
}
else
{
// Leer datos de sensor y codificar (Libreria LoRa_Serialization).
am2315_readedData data = readAM2315Data();
encoder.writeTemperature(data.temp);
encoder.writeHumidity(data.hum);
// Comentar las dos lineas "encoder" para enviar texto plano
// Send packet
LMIC_setTxData2(1, mydata, sizeof(mydata), 0);
if (isLoopRunning)
{
freq = String(LMIC.freq);
Serial.println("-->Packet queued using freq = " + freq);
// Prepare upstream data transmission at the next possible time.
printSensorInfoInDisplay(data.temp, data.hum);
printLoraSentInDisplay(freq);
}
}
// Next TX is scheduled after TX_COMPLETE event.
}
ملاحظة : عانى خطأ يمنع العقدة من تلقي الحزم الخلفية ، لذلك كان من المستحيل مصادقة الجهاز أمام الخادم. تمت إضافته في إعداد العميل () (بشكل أكثر تحديداً في دالة LoRawan_StartJob () لملف lorawan.cpp ) خط الكود التالي الذي يزيد من خطأ الساعة القصوى بنسبة 10 ٪:
LMIC_setClockError(MAX_CLOCK_ERROR * 10 / 100);
تقدم كل من ChirpStack و Things Network سلسلة من التكامل لإرسال البيانات التي يتلقاها خادمنا للخدمات الأخرى. على سبيل المثال: يمكننا إرسال البيانات إلى قاعدة بيانات التأثير ، والاستفادة من MQTT ، أو الاتصال بخدمات AWS أو Azure ...
في هذا القسم ، سيتم رؤية حالة عملية يمكننا فيها استخدام تكامل HTTP (Webhooks in the Things Network) و MQTT لإرسال البيانات التي ترسلها أجهزتنا وأن خادمنا يتلقى لتطبيق خاص به.
للوصول إلى التكامل:
في حالة استخدام chirpstack نحن مهتمون
في كلا الخادمين ، يعمل هذا التكامل بطريقة مماثلة: قم بتشغيل حدث في كل مرة يرسل فيها جهاز التطبيق معلومات (في حالة TTN ، يجب أن نضع علامة على مربع رسالة الوصلة الصاعدة ) ، وبهذه المعلومات ، يتم إطلاق ما بعد طلب HTTP من نوع ما إلى عنوان URL الذي يشير إليه.
ملاحظة: ممارسة جيدة ، إما للتحقق من أن الحدث يتم إطلاقه بشكل صحيح أو لتصور تنسيق البيانات هو الوصول إلى خدمة postbin ، حيث يمكننا إنشاء صندوق (عنوان URL المؤقت لتلقي الطلبات).
ملاحظة 2: إذا كان التطبيق الذي ستطلقه هو وضع الالتماس في LocalHost وخادم ChirpStack أيضًا (بطريقة موثوقة كما هو موضح في هذه الوثائق) ، فسيتعين عليك الإشارة إلى عنوان URL على النحو التالي:
http://host.docker.internal:PUERTO/uri
لا يغطي هذا الوثائق سوى استخدام chirpstack ولا يتم توثيق TTN لإرسال البيانات (له تنسيق مختلف في الالتماس).
إذا تم فك تشفير البيانات بأمثلة من هذا المستودع (المجلد Decoders-Integrations ) ، فسوف نحصل على جسم في الطلب مما يلي:
{
"applicationID": 0,
"applicationName": "Name",
"deviceName": "DeviceName",
"devEUI": "BYTES_EUI",
"txInfo": [Object object],
"adr": true,
"dr": 5,
"fCnt": 24,
"fPort": 1,
"data": "DATA_WITHOUT_DECODE",
"objectJSON": {
"data":"DATA_WITHOUT_DECODE==",
"decodedData":{
"humidity":37,"temperature":23
},
"message":"Informacion recibida del nodo"
},
"tags": [Object object],
"confirmedUplink": false,
"devAddr": "BYTES_DEV_ADDR"
}
ObjectJson هو الكائن الذي تم إرجاعه بواسطة وظيفة فك التشفير لدينا.
لقراءته ، على سبيل المثال في تطبيق JavaScript ، سيكون كافياً للقيام بشيء مشابه لما يلي (المزيد في الملف /Decoders-Integrations/arduino_Chirpstack_Http_Integration.js )
const { deviceName, objectJSON, devAddr} = req.body;
var sensorData = JSON.parse(objectJSON);
//devAddr esta codificado!
var temperature = sensorData.decodedData.temperature;
var humidity = sensorData.decodedData.humidity;
في الواقع ، ما لم نستخدم MQTTS (MQTT مع TLS) ، فلن يكون من الضروري الوصول إلى أي تكامل من تطبيق الويب الخادم.
في هذا المثال ، سنوقع على تطبيقنا على الموضوع الذي سيرسل إليه جهازنا النهائي البيانات.
إذا تم إطلاق تطبيقنا في المنزل وخادم ChirpStack أيضًا (تم قياسه كما أظهرنا في هذه الوثائق) ، فسيكون مضيف الوسيط هو IP لجهاز WSL. لمعرفة هذه البيانات سنطلقها:
wsl hostname -I
سيتعين عليك أيضًا إجراء بعض التكوينات عن طريق إطلاق الأوامر التالية (1883 هو منفذ البعوض ، إذا تم تعديله الآخر):
netsh interface portproxy add v4tov4 listenport=1883 listenaddress=0.0.0.0 connectport=1883 connectaddress=127.0.0.1
يمكننا استخدام MQTT كما هو الحال في مثال Docker ، مع المعلمة المجهولة مع قيمة TRU (دون استخدام أي نوع من كلمة المرور أو قائمة المستخدمين) أو يمكننا تكوين قائمة من المستخدمين (لكل منها موضوعات يمكنها القراءة أو الكتابة) مع كلمات المرور الخاصة بهم (كما هو موضح في الوثائق التالية).
للقيام بذلك ، سنقوم بتشغيل الأوامر التالية (يمكننا تشغيلها من WSL ) ، سيطلب منا كل واحد منهم تقديم كلمة مرور لكل مستخدم (في هذا المثال تم استخدام تمريرة للجميع):
# Create a password file, with users chirpstack_gw, chirpstack_ns, chirpstack_as, bob and nodeApp
sudo mosquitto_passwd -c /etc/mosquitto/passwd chirpstack_gw
sudo mosquitto_passwd /etc/mosquitto/passwd chirpstack_ns
sudo mosquitto_passwd /etc/mosquitto/passwd chirpstack_as
sudo mosquitto_passwd /etc/mosquitto/passwd bob
sudo mosquitto_passwd /etc/mosquitto/passwd nodeApp
# Optional, Secure the password file
sudo chmod 600 /etc/mosquitto/passwd
سيؤدي ذلك إلى إنشاء ملف passwd الذي سيحتوي على جميع المستخدمين وكلمات المرور ، يمكننا الآن تكوين قائمة ACLS في ملف متجانس مثل ما يلي:
user chirpstack_gw
topic write gateway/+/event/+
topic read gateway/+/command/+
user chirpstackns
topic read gateway/+/event/+
topic write gateway/+/command/+
user chirpstack_as
topic write application/+/device/+/event/+
topic read application/+/device/+/command/+
user bob
topic read application/123/device/+/event/+
topic write application/123/device/+/command/+
user nodeApp
topic read application/+/device/#
topic write application/+/device/#
الآن ، يجب علينا تعديل تكوين الخادم لاستخدام بيانات الاعتماد هذه عن طريق تعديل الملفات المقدمة في /chirpstack-docker/configuration :
[application_server.integration.mqtt]
server="tcp://mosquitto:1883"
username="chirpstack_as"
password="pass"
[integration.mqtt.auth.generic]
servers=["tcp://mosquitto:1883"]
username="chirpstack_gw"
password="pass"
[network_server.gateway.backend.mqtt]
server="tcp://mosquitto:1883"
username="chirpstack_ns"
password="pass"
listener 1883
password_file /mosquitto/config/passwd
acl_file /mosquitto/config/acls
allow_anonymous false
mosquitto:
image: eclipse-mosquitto:2
ports:
- 1883:1883
volumes:
- ./configuration/eclipse-mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf
- ./configuration/eclipse-mosquitto/passwd:/mosquitto/config/passwd
- ./configuration/eclipse-mosquitto/acls:/mosquitto/config/acls
في هذا المثال ، سنستخدم تطبيق NodeJS للاتصال بخادم ChirpStack المحلي المحلي. يمكن العثور على جميع الكود في /Decoders-Integrations/arduino_Chirpstack_mqtt_Integration.js integrates/arduino_chirpstack_mqtt_integration.js.
أولاً ، سيتعين علينا تثبيت حزمة MQTT
npm install mqtt --save
معه ، يمكننا بالفعل الاتصال بالوسيط:
var mqtt = require('mqtt')
const host = 'WSL_IP'
const port = '1883' //or your port
const clientId = 'mqtt_NodeApp_' + Math.random().toString(16).slice(3)
const connectUrl = 'mqtt://' + host + ':' + port;
const client = mqtt.connect(connectUrl, {
clientId,
clean: true,
//username: "nodeApp", //Descomentar si usamos contraseñas y acls
//password: "pass", //Colocar el usuario y contraseña correspondiente
connectTimeout: 4000,
reconnectPeriod: 1000,
debug: true
})
والاشتراك في الموضوع المطلوب (الحرف # هو بطاقة برية متعددة المستويات ، فهذا يعني أننا نقرأ أي طوابق فرعية ، في حين أن الحرف + عبارة عن علامة برية واحدة).
const chirpstackApplicationID = 1; //Check url, for example: http://localhost:8080/#/organizations/1/applications. /1/ is the ID
const chirpstackDeviceID = "DEV_EUI";
const chirpstackReadAppTopic = "application/" + chirpstackApplicationID + "/device/#";
const chirpstackWriteAppTopic = "application/" + chirpstackApplicationID + "/device/"+chirpstackDeviceID+"/EXAMPLE";
سوف نستخدم الأحداث التالية لهذا:
//Evento al conectarse
client.on('connect', function () {
console.log("Connected")
client.subscribe(chirpstackReadAppTopic, function (err) {
if (!err) {
console.log("Subscribed to topic: "+chirpstackReadAppTopic)
//client.publish(chirpstackWriteAppTopic, 'Hello mqtt') //Podemso enviar un mensaje para debugear
}
else {
console.log("Error in connection:")
console.log(err)
}
})
})
//Evento al recibir un mensaje
client.on('message', function (topic, message) {
// El mensaje es un buffer, convertimos a String.
var stringMsg = message.toString();
console.log(topic + " - " + stringMsg)
insertSensorEntry_Mqtt(topic, stringMsg); //Funcion que lee el mensaje e inserta en base de datos
})
في كلا الخادمين (chirpstack وشبكة الأشياء) يسمى التكامل MQTT ، نعم ، قبل إجراء أي تكامل يجب علينا تكوين الشهادات.
A continuación se documentará como realizar la integración con MQTT en un servidor local de Chirpstack (para más info revisar el apartado ChirpStack privado en local de esta documentación).
Antes de generar los certificados, debemos tener instalado CFSSL & CFSSLJSON. Tras ello, clonaremos el siguiente repositorio propiedad del creador de Chirpstack y seguiremos los pasos de su documentación: Chirpstack-Certificates.
NOTA: Si se usa Windows, instalar los pre-requisitos en la máquina WSL pues se necesitará hacer uso del comando make .
Colocamos la carpeta certs generada con el proyecto Chirpstack-Certificates en nuestro proyecto Chirpstack-Docker . Después modificados el archivo docker-compose.yml para añadir a cada contenedor el volumen que contendrá los certificados correspondientes.
Seguimos siguiendo la documentación del proyecto Chirpstack-Certificates para realizar todas las modificaciones pertinentes en la configuración del servidor:
Como hemos visto anteriormente, el evento que se lanza al recibir un mensaje llama a una función que lee el mensaje recibido y lo descodifica.
El formato del mensaje recibido (si hemos usado los descodificadores del ejemplo) es una cadena de texto con el siguiente contenido:
{"applicationID":"1","applicationName":"APP_NAME","deviceName":"DEV_NAME","devEUI":"DEV_ADDRESS", "txInfo":{"frequency":868500000,"dr":5},"adr":true,"fCnt":2, "fPort":1,"data":"DATA","object":{"data":"DATA","decodedData":{"humidity":0,"temperature":-327},"message":"Informacion recibida del nodo"}}
Y es lo que buscamos leer en la siguiente función:
function insertSensorEntry_Mqtt(topic, msg){
console.log("INSERTAMOS DATO DE SENSOR RECIBIDO POR MQTT EN TOPICO: "+topic);
const parseMsg = JSON.parse(msg); //Recordar haber hecho un ToString al buffer antes!
var deviceName = parseMsg.deviceName;
var devAddr = parseMsg.devEUI; //No codificado
var temperature = parseMsg.object.decodedData.temperature;
var humidity = parseMsg.object.decodedData.humidity;
var success = true;
}
object es el objeto retornado por nuestra función Decoder .
Como bien se sabe, la tasa de transferencia de LoRA es muy baja, lo que provoca una gran perdida de paquetes y una enorme latencia cuando se envía información:
Algunos expertos indican que es necesario cierta distancia entre los dispositivos (30m y preferiblemente algún obstaculo entre ellos) para que la comunicación sea más fluida. No ha sido probado y solo se ha lanzado con las dos tarjetas en un extremo cada una de un piso.
Por otro lado se hace uso de versiones antiguas de LoRaWAN (1.0.2 y 1.0.3) que tienen problemas de seguridad que se solventan en parte en las siguientes versiones (1.0.4 y 1.1.0, esta última también implementa re-conectividad en caso de desconectarse de la red LoRaWAN), pero no se dispone de librerias para trabajar con ellas.
Esto no quita que esta técnología pueda ser muy interesante y útil en el futuro debido a no depender de proveedores externos (de comunicaciones y electricidad), siendo una opción ecónomica y muy llamativa para utilizar en proyectos IoT de grandes ciudades o entornos rurales.
Este proyecto ha sido realizado para la Fundación CTIC, su uso es libre y no es necesarío ningún crédito en su uso (Revisar las licencia de las librerias utilizadas).