কখনও একটি প্রকল্পে উপস্থিতি বা অবস্থান ট্র্যাকিং যোগ করতে চান? সমাধান (বা এর অভাব) দেখে হতাশ?
চিন্তা করবেন না, আপনি একা নন!
এই পোস্টে আপনি শিখবেন কিভাবে একটি খুব মৌলিক ট্র্যাকিং এবং বিজ্ঞপ্তি অ্যাপ্লিকেশন বাস্তবায়ন করতে হয়। আমরা একটি কণা আর্গন এবং একটি টাইল মেট ব্যবহার করব৷
শেষ পর্যন্ত আপনি বলতে পারবেন কখন টাইলটি উপস্থিত আছে বা নেই৷ এছাড়াও আমরা আপনার পছন্দের ডিভাইসগুলিতে পুশ বিজ্ঞপ্তি পাঠাতে Pushover ব্যবহার করব।
চলুন চলুন!
দ্রষ্টব্য আমরা শুরু করার আগে, এই পোস্টটি দীর্ঘ . আপনি PDF সংস্করণটি ডাউনলোড করতে পারেন যাতে আপনি এটি সংরক্ষণ করতে এবং পরে দেখতে পারেন৷
প্রাথমিক তদন্ত
একটি টাইল ব্যবহার করার ধারণা প্রথম নজরে সুস্পষ্ট ছিল না। আদর্শভাবে, একটি ফোন ব্যবহার করা আরও অর্থপূর্ণ বলে মনে হচ্ছে। দুর্ভাগ্যক্রমে, এটি একটি কার্যকর বিকল্প হিসাবে ছিল না। এটির জন্য আরও কিছু গবেষণা এবং একটি ব্লুটুথ iOS অ্যাপ তৈরির প্রয়োজন হবে৷
৷সুতরাং, একটি ফোন ব্যবহার করার ধারণা আউট ছিল.
তারপর আমি ভাবলাম, "কি ডিভাইসগুলি করবে৷ সব সময় বিজ্ঞাপন?
এটাই আমাকে টাইলের মতো ট্র্যাকারের পথে নিয়ে গেছে।
এটি আসার পরে কিছু প্রথাগত পরীক্ষা ছিল। প্রথম থামুন, টাইল অ্যাপ্লিকেশন।
আমি সংযোগ এবং ডিভাইস ব্যবহার করতে সক্ষম ছিল. আমি এমনকি এটি একটি আকর্ষণীয় সুর বাজান. ?
তারপর, আমি ব্লুটুথ স্ক্যানার অ্যাপ্লিকেশনগুলির একটি ব্যবহার করতে চলেছি। আমি সমস্ত ফলাফল এবং বিঙ্গো মাধ্যমে স্ক্রোল. টাইল ছিল!
আমি এমনকি কয়েক ঘন্টা অপেক্ষা করেছি এবং এটি আবার পরীক্ষা করেছি। আমি নিশ্চিত করতে চেয়েছিলাম যে এটি কিছুক্ষণ পরে ঘুমাতে না যায়। সক্রিয় আউট, এটা সবসময় বিজ্ঞাপন. যতদূর আমি বলতে পারি, প্রায় প্রতি 8 সেকেন্ডে।
এই সমস্ত পরীক্ষা একটি উপসংহারে নিয়ে যায়:এটি সহজেই উপস্থিতি সনাক্তকরণের জন্য ব্যবহার করা যেতে পারে৷
প্রক্রিয়ার পরবর্তী ধাপটি ছিল কীভাবে এটি একটি আর্গনের সাথে কাজ করা যায় তা বের করার চেষ্টা করছিল৷
৷বিজ্ঞাপন
আমরা আগের ধাপে যেমন জড়ো হয়েছিলাম, আমরা জানি যে টাইল প্রতি 8 সেকেন্ডে বিজ্ঞাপন দিচ্ছে। এর মানে আর্গন, জেনন বা বোরন সহ যেকোনো ডিভাইস ব্যবহার করার জন্য এটি সহজেই স্ক্যান করা উচিত।
এই উদাহরণের জন্য আমি আপনাকে একটি আর্গন ব্যবহার করার পরামর্শ দিই। কারণ ব্লুটুথ এবং মেশ একই রেডিও শেয়ার করে। টাইলের জন্য স্ক্যান করার সময়, জালের সাথে সংযুক্ত জেনন প্রায়শই বিজ্ঞাপনের প্যাকেটগুলি মিস করে। এটি মিথ্যা নেতিবাচক (এবং হতাশা!) নিয়ে যাবে।
একই লাইনে, আপনি নিশ্চিত করতে চাইবেন যে আপনার Argon কোনো মেশ নেটওয়ার্কের সাথে সংযুক্ত নয়। আপনি CLI ব্যবহার করে এটি অপসারণ করতে পারেন। আপনার কম্পিউটারে আপনার ডিভাইস সংযুক্ত করুন এবং নিম্নলিখিত কমান্ডটি চালান:
particle mesh remove <device name/ID>
নিশ্চিত করুন যে আপনি
ঠিক আছে, ভালো জিনিসে ফিরে আসি।
ব্লুটুথ-এ বিজ্ঞাপনের কয়েকটি ভিন্ন উদ্দেশ্য থাকতে পারে। সাধারণত যদিও, এটি জোড়ার পর্বের শুরুকে চিহ্নিত করে। এইভাবে অন্যান্য ডিভাইসগুলি জানে যে বিজ্ঞাপন ডিভাইসটি উপলব্ধ৷
৷উপরন্তু, বিজ্ঞাপন ডিভাইস কি পরিষেবা আছে তা নির্দেশ করবে। মেলে না এমন ডিভাইসগুলিকে ফিল্টার করতে আমরা এই জ্ঞান ব্যবহার করতে পারি।
উদাহরণস্বরূপ, এখানে টাইল ডিভাইসে উপলব্ধ পরিষেবাগুলির একটি স্ক্রিনশট রয়েছে:
স্ক্যান করার সময় আমরা দুবার চেক করব যে আমরা যে ডিভাইসে সংযোগ করছি তাতে 0xfeed
পরিষেবা UUID আছে কিনা। .
যদিও আমরা ব্লুটুথ ল্যান্ডের গভীরে যাওয়ার আগে, আসুন লগার ব্যবহার করে ডিবাগ করার জন্য আমাদের অ্যাপ সেট আপ করি৷
লগ করা
৷
এই টিউটোরিয়ালে আমরা Logger ব্যবহার করব। এটি আপনাকে particle serial monitor
ব্যবহার করে আপনার অ্যাপ থেকে লগ বার্তা প্রদর্শন করতে দেয় .
লগার সম্পর্কে শীতল বৈশিষ্ট্যগুলির মধ্যে একটি হল বার্তা অনুক্রমের ধারণা। এটি আপনাকে ডিজাইনারকে বেছে বেছে বার্তাগুলিকে নিঃশব্দ করতে দেয় যা প্রয়োজন নাও হতে পারে৷
৷
উদাহরণস্বরূপ, যদি আপনার কাছে ডিবাগিংয়ের জন্য ব্যবহৃত বার্তা থাকে। আপনি তাদের অপসারণ বা তাদের মন্তব্য আউট করতে পারেন. অথবা, আপনি LOG_LEVEL
বাড়াতে পারেন তাই তারা কার্যকরভাবে উপেক্ষা করা হয়।
এখানে লগিং লেভেল রয়েছে যা logging.h
এ উপলব্ধ পার্টিকেলের ডিভাইস-ওএস রিপোজিটরিতে:
// Log level. Ensure log_level_name() is updated for newly added levels
typedef enum LogLevel {
LOG_LEVEL_ALL = 1, // Log all messages
LOG_LEVEL_TRACE = 1,
LOG_LEVEL_INFO = 30,
LOG_LEVEL_WARN = 40,
LOG_LEVEL_ERROR = 50,
LOG_LEVEL_PANIC = 60,
LOG_LEVEL_NONE = 70, // Do not log any messages
// Compatibility levels
DEFAULT_LEVEL = 0,
ALL_LEVEL = LOG_LEVEL_ALL,
TRACE_LEVEL = LOG_LEVEL_TRACE,
LOG_LEVEL = LOG_LEVEL_TRACE, // Deprecated
DEBUG_LEVEL = LOG_LEVEL_TRACE, // Deprecated
INFO_LEVEL = LOG_LEVEL_INFO,
WARN_LEVEL = LOG_LEVEL_WARN,
ERROR_LEVEL = LOG_LEVEL_ERROR,
PANIC_LEVEL = LOG_LEVEL_PANIC,
NO_LOG_LEVEL = LOG_LEVEL_NONE
} LogLevel;
কুল, লগ লেভেল। কিন্তু আমরা কিভাবে তাদের ব্যবহার করব?
আমরা এই ফাংশনগুলির একটির মাধ্যমে তাদের ব্যবহার করতে পারি:
Log.trace
, Log.info
, Log.warn
, Log.error
.
যেমন:
Log.trace("This is a TRACE message.");
যদি আমরা লগ লেভেল LOG_LEVEL_INFO
সেট করি আমরা শুধুমাত্র Log.info
থেকে বার্তা দেখতে পাব , Log.warn
, এবং Log.error
. LOG_LEVEL_WARN
? শুধুমাত্র Log.warn
এবং Log.error
প্রদর্শিত হবে (আশা করি আপনি ধারণা পেয়েছেন।)
এটি সেট আপ করতে, আমরা ডিফল্ট স্তরটিকে LOG_LEVEL_ERROR
এ সেট করব৷ . এছাড়াও আমরা অ্যাপ নির্দিষ্ট LOG_LEVEL
সেট করব LOG_LEVEL_TRACE
এ . শেষ ফলাফলটি এরকম কিছু হওয়া উচিত
// For logging
SerialLogHandler logHandler(115200, LOG_LEVEL_ERROR, {
{ "app", LOG_LEVEL_TRACE }, // enable all app messages
});
এইভাবে আমরা DeviceOS লগ বার্তাগুলির সাথে স্প্যাম করি না৷ এছাড়াও, আমরা অ্যাপ থেকেই সমস্ত প্রযোজ্য বার্তা পাই।
যাইহোক, আপনি যদি আপনার ডিভাইসটিকে একটি LOG_LEVEL
এ সেট করতে চান আপনি এটি এভাবে সেট আপ করতে পারেন:
SerialLogHandler logHandler(LOG_LEVEL_INFO);
আপনি পার্টিকেলের ডিভাইসওএস ব্যবহার করে আপনার যাত্রা চালিয়ে যাওয়ার সাথে সাথে আপনি শীঘ্রই বুঝতে পারবেন এটি কতটা সুবিধাজনক হতে পারে। এখন, ভালো জিনিসের দিকে যাওয়া যাক!
এটি সেট আপ করা হচ্ছে
প্রথমে, আমরা নিশ্চিত করতে চাই যে আমরা DeviceOS এর সঠিক সংস্করণ ব্যবহার করছি। 1.3 এর পরের যেকোনো সংস্করণে ব্লুটুথ থাকবে। আপনি এখানে নির্দেশাবলী পেতে পারেন।
পরবর্তী আমরা টাইলের জন্য স্ক্যান করা শুরু করতে চাই। আমরা loop()
এ এটি করতে চাই একটি নির্দিষ্ট ব্যবধানে ফাংশন। আমরা একটি millis()
ব্যবহার করব এই ক্ষেত্রে টাইমার:
// Scan for devices
if( (millis() > lastSeen + TILE_RE_CHECK_MS) ){
BLE.scan(scanResultCallback, NULL);
}
নিশ্চিত করুন যে আপনি lastSeen
সংজ্ঞায়িত করেছেন ফাইলের শীর্ষে যেমন:
system_tick_t lastSeen = 0;
শেষবার টাইলটি "দেখা হয়েছে" ট্র্যাক করতে আমরা এটি ব্যবহার করব। অর্থাৎ শেষবার যখন আর্গন টাইল থেকে একটি বিজ্ঞাপনের প্যাকেট দেখেছিল৷
TILE_RE_CHECK_MS
হিসাবে সংজ্ঞায়িত করা যেতে পারে
#define TILE_RE_CHECK_MS 7500
এইভাবে আমরা প্রতি 7.5 সেকেন্ডে বিজ্ঞাপনের প্যাকেটের জন্য খুব ন্যূনতম পরীক্ষা করছি।
টাইল ডিভাইস খুঁজে পেতে আমরা BLE.scan
ব্যবহার করব . যখন আমরা এটিকে কল করি, এটি স্ক্যানিং প্রক্রিয়া শুরু করবে। যেমন ডিভাইস পাওয়া যায় scanResultCallback
ফায়ার করবে।
আপাতত, আমরা scanResultCallback
সংজ্ঞায়িত করতে পারি ফাইলের শীর্ষে:
void scanResultCallback(const BleScanResult *scanResult, void *context) {
}
আপনি লক্ষ্য করেছেন যে এতে একটি BleScanResult
রয়েছে . এতে ঠিকানা, RSSI এবং ডিভাইসের নাম (যদি পাওয়া যায়) এবং উপলব্ধ পরিষেবার তথ্য থাকবে। এটি পরে কাজে আসবে যখন আমরা আমাদের টাইল ডিভাইস খুঁজছি!
মনে রাখবেন, সেই BLE.scan
স্ক্যানিং শেষ না হওয়া পর্যন্ত ফিরে আসে না। স্ক্যান করার জন্য ডিফল্ট সময়সীমা 5 সেকেন্ড। আপনি BLE.setScanTimeout()
ব্যবহার করে সেই মান পরিবর্তন করতে পারেন . setScanTimeout
10ms বৃদ্ধিতে ইউনিট লাগে। সুতরাং, একটি 500ms টাইমআউটের জন্য 50 এর মান প্রয়োজন।
এই অ্যাপের ক্ষেত্রে, আমি 8s (8000ms) এর মান ব্যবহার করার সুপারিশ করব। আপনি এটি এভাবে সেট করতে পারেন:
BLE.setScanTimeout(800);
এই ক্ষেত্রে, ডিভাইসটি স্ক্যান করবে যতক্ষণ পর্যন্ত বিজ্ঞাপন দিতে টাইল লাগে। এইভাবে এটি একটি বিজ্ঞাপন প্যাকেট মিস করার সম্ভাবনা কম।
স্ক্যান ফলাফল পরিচালনা করা
এখন আমাদের কাছে scanResultCallback
আছে ভিতরে কি ঘটছে তা সংজ্ঞায়িত করা যাক।
আমরা প্রথমে বিজ্ঞাপন ডেটার ভিতরে পরিষেবার তথ্য পেতে চাই। সর্বোত্তম উপায় হল scanResult->advertisingData.serviceUUID
ব্যবহার করা . আমরা UUID-এর একটি অ্যারেতে পাস করব যা আমাদের ব্যবহারের জন্য অনুলিপি করা হবে।
BleUuid uuids[4];
int uuidsAvail = scanResult->advertisingData.serviceUUID(uuids,sizeof(uuids)/sizeof(BleUuid));
এটি uuids
পপুলেট করবে যে ভাবে আপনি তাদের উপর পুনরাবৃত্তি করতে পারেন. uuidsAvail
উপলব্ধ UUID এর পরিমাণ সমান হবে।
আমাদের ক্ষেত্রে আমরা একটি নির্দিষ্ট UUID খুঁজছি। আমরা এটিকে ফাইলের শীর্ষে সংজ্ঞায়িত করব:
#define TILE_UUID 0xfeed
সাধারণত UUID অনেক হয় দীর্ঘ এর মতো একটি সংক্ষিপ্ত UUID মানে এটি সংরক্ষিত বা ব্লুটুথ স্পেসিফিকেশনের অংশ। উভয় ক্ষেত্রেই আমরা এটির জন্য একইভাবে পরীক্ষা করব যেভাবে আমরা একটি 32 বিট বা 128 বিট সংস্করণ পরীক্ষা করব।
ডায়াগনস্টিক কারণে আমরা ডিভাইসের তথ্যও প্রিন্ট করতে পারি। এই ক্ষেত্রে RSSI এবং ডিভাইস MAC ঠিকানা সহজ:
// Print out mac info
BleAddress addr = scanResult->address;
Log.trace("MAC: %02X:%02X:%02X:%02X:%02X:%02X", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
Log.trace("RSSI: %dBm", scanResult->rssi);
অবশেষে পাওয়া ডিভাইসটিতে UUID আছে কিনা তা দেখার জন্য একটি লুপ সেট আপ করা যাক:
// Loop over all available UUIDs
// For tile devices there should only be one
for(int i = 0; i < uuidsAvail; i++){
// Print out the UUID we're looking for
if( uuids[i].shorted() == TILE_UUID ) {
Log.trace("UUID: %x", uuids[i].shorted());
// Stop scanning
BLE.stopScanning();
return;
}
}
আমরা সহজেই UUID এর "সংক্ষিপ্ত" সংস্করণটিকে TILE_UUID
এর সাথে তুলনা করতে পারি . এটি একটি সাধারণ পূর্ণসংখ্যা তাই কোনো জটিল মেমরি তুলনা অপারেশনের প্রয়োজন নেই। সুতরাং, if( uuids[i].shorted() == TILE_UUID )
ব্যবহার করে ঠিক কাজ করে।
এছাড়াও আপনি Log.trace
ব্যবহার করতে পারেন ডায়াগনস্টিক তথ্য মুদ্রণ করতে। এই ক্ষেত্রে আমরা shorted()
প্রিন্ট করার জন্য এটি ব্যবহার করছি UUID এর সংস্করণ।
এটি পরীক্ষা করুন!
৷এখন পর্যন্ত আমাদের যা আছে তা পরীক্ষা করা যাক!
আপনার Argon এ অ্যাপ্লিকেশন প্রোগ্রাম. টার্মিনাল খুলুন এবং particle serial monitor
চালান ডিবাগ বার্তা দেখতে। আপনি যা দেখতে পারেন তার একটি উদাহরণ এখানে:
0000005825 [app] TRACE: MAC: 65:C7:B3:AF:73:5C
0000005827 [app] TRACE: RSSI: -37Bm
0000005954 [app] TRACE: MAC: B3:D9:F1:F0:5D:7E
0000005955 [app] TRACE: RSSI: -62Bm
0000006069 [app] TRACE: MAC: C5:F0:74:3D:13:77
0000006071 [app] TRACE: RSSI: -62Bm
0000006217 [app] TRACE: MAC: 65:C7:B3:AF:73:5C
0000006219 [app] TRACE: RSSI: -39Bm
0000006224 [app] TRACE: MAC: B3:D9:F1:F0:5D:7E
0000006225 [app] TRACE: RSSI: -62Bm
0000006296 [app] TRACE: MAC: D7:E7:FE:0C:A5:C0
0000006298 [app] TRACE: RSSI: -60Bm
0000006299 [app] TRACE: UUID: feed
লক্ষ্য করুন কিভাবে বার্তাটিতে TRACE
অন্তর্ভুক্ত রয়েছে এবং এছাড়াও [app]
? এর মানে এটি একটি ট্রেস বার্তা যা অ্যাপ্লিকেশন কোড থেকে উদ্ভূত। কাজ ঠিক?
এই কোডটি দ্রুত স্প্যামি হয়ে যায়, বিশেষ করে যদি আপনি প্রচুর বিজ্ঞাপনী ব্লুটুথ ডিভাইসের পরিবেশে থাকেন। আপনি টাইল চালু থাকলে এবং শেষ পর্যন্ত আপনি একটি বার্তা দেখতে পাবেন UUID: feed
. তার মানে আপনার আর্গন টাইল খুঁজে পেয়েছে!
এরপর আমরা টাইলের ঠিকানা মেমরিতে "প্রোগ্রাম" করতে অনবোর্ড মোড বোতামটি ব্যবহার করব। এইভাবে আমরা এমন সমস্ত ডিভাইস ফিল্টার আউট করতে পারি যেগুলি আমরা যত্ন করি না৷
৷বোতামে ডিভাইস যোগ করুন
প্রথমে আমাদের মোড বোতামটি কীভাবে নিরীক্ষণ করা যায় তা বের করতে হবে। ডকুমেন্টেশন অনুযায়ী সর্বোত্তম বাজি হল System.on
ব্যবহার করা .
System.on(button_click, eventHandler);
প্রথম যুক্তি হল সিস্টেম ইভেন্টের নাম। আমাদের ক্ষেত্রে এটি button_click
. দ্বিতীয় যুক্তি হল একটি ইভেন্ট হ্যান্ডলার ফাংশন। আমরা একে বলব eventHandler
আপাতত।
এখন eventHandler
তৈরি করা যাক
void eventHandler(system_event_t event, int duration, void* )
{
}
গুরুত্বপূর্ণ: আপনি Log
ব্যবহার করতে পারবেন না eventHandler
এর ভিতরে ফাংশন . এটি পরীক্ষা করার একটি সহজ উপায় হল D7 এ LED টগল করা। এটা সেট আপ করা যাক!
setup()
-এ LED আরম্ভ করুন
// Set LED pin
pinMode(D7,OUTPUT);
তারপর আমরা এটিকে eventHandler
এর ভিতরে যোগ করতে পারি
if( event == button_click ) {
if( digitalRead(D7) ) {
digitalWrite(D7,LOW);
} else {
digitalWrite(D7,HIGH);
}
}
আমরা তখন D7 (অনবোর্ড নীল LED) এ লিখতে পারি। এমনকি আমরা digitalRead
ব্যবহার করতে পারি LED এর অবস্থা কী তা পড়তে। এটি HIGH
দিয়ে প্রতিক্রিয়া জানাবে অথবা LOW
পরিস্থিতির উপর নির্ভর করে
ডিভাইসে ফার্মওয়্যার লোড করুন এবং আমাদের নীল LED এর উপর চমৎকার নিয়ন্ত্রণ থাকবে!
পরবর্তী বিভাগে, আমরা ডিভাইসটিকে "লার্নিং" মোডে রাখতে মোড বোতামটি ব্যবহার করব। এটি আমাদের টার্গেট টাইল ডিভাইসের সাথে এক টাচ সেটআপ করার অনুমতি দেবে৷
EEPROM এ ঠিকানা সংরক্ষণ করা হচ্ছে
এই পরবর্তী ধাপে আমরা টাইলের ঠিকানা EEPROM-এ সংরক্ষণ করব। এইভাবে যখন ডিভাইসটি পুনরায় চালু হয় বা শক্তি হারায় তখনও আমরা পরবর্তীতে টাইল সনাক্ত করতে সক্ষম হব।
যদিও একটি দীর্ঘস্থায়ী প্রশ্ন আছে। প্রথম স্থানে ঠিকানা সংরক্ষণ করার জন্য আমরা এটি কিভাবে পেতে পারি?
বোতাম প্রেস নিরীক্ষণ করে, আমরা ডিভাইসটিকে একটি "লার্নিং" মোডে রাখতে পারি। ডিভাইসটি একটি টাইলের জন্য স্ক্যান করবে, এবং এটি খুঁজে পেলে ঠিকানাটি সংরক্ষণ করবে৷
৷
প্রথমে if( uuids[i].shorted() == TILE_UUID )
এর মধ্যে একটি শর্তসাপেক্ষ যোগ করা যাক :
// If we're in learning mode. Save to EEPROM
if( isLearningModeOn() ) {
searchAddress = scanResult->address;
EEPROM.put(TILE_EEPROM_ADDRESS, searchAddress);
setLearningModeOff();
}
আমরা "লার্নিং মোডে" আছি তা জানার উপায় হিসেবে আমরা D7-এর স্ট্যাটাস ব্যবহার করব। আমরা digitalRead(D7)
ব্যবহার করে D7 পড়ে এটি করি . আসুন একটি ফাংশন তৈরি করি যা এটিকে আরও স্পষ্ট করে:
bool isLearningModeOn() {
return (digitalRead(D7) == HIGH);
}
এছাড়াও আমরা digitalWrite(D7,LOW);
প্রতিস্থাপন করতে পারি এবং digitalWrite(D7,HIGH);
অনুরূপ ফাংশন সহ। এইভাবে আমরা যা করছি তা আরও সোজা।
// Set "Learning mode" on
void setLearningModeOn() {
digitalWrite(D7,HIGH);
}
// Set "Learning mode" off
void setLearningModeOff() {
digitalWrite(D7,LOW);
}
তারপর, আমরা একটি গ্লোবাল ভেরিয়েবল searchAddress
বরাদ্দ করি স্ক্যান ফলাফল হিসাবে। আমরা searchAddress
সেট আপ করি ফাইলের শীর্ষে এটির মতো:
BleAddress searchAddress;
এরপরে আমরা EEPROM.put
ব্যবহার করে এটিকে অ-উদ্বায়ী মেমরিতে সংরক্ষণ করতে চাই . TILE_EEPROM_ADDRESS
0xa
হিসাবে সংজ্ঞায়িত করা হয় . আপনি TILE_EEPROM_ADDRESS
সংজ্ঞায়িত করতে পারেন মেমরি ঠিকানা আপনার অভিনব সুড়সুড়ি যাই হোক না কেন ব্যবহার করতে. এখানে ফাইলের শীর্ষে সম্পূর্ণ সংজ্ঞা দেওয়া আছে।
#define TILE_EEPROM_ADDRESS 0xa
অবশেষে, আমরা setLearningModeOff()
ব্যবহার করে LED এবং "লার্নিং মোড" বন্ধ করি
প্রতিবার একটি ডিভাইস পাওয়া গেলে আমরা millis()
ব্যবহার করব lastSeen
সেট করতে . উপরন্তু, আমরা lastRSSI
ব্যবহার করে শেষ RSSI ট্র্যাক করতে পারি . ডিভাইসটি কতটা কাছাকাছি তা জানার এটি একটি সস্তা উপায়। আমরা scanResult->rssi
ব্যবহার করব এই তথ্য পেতে এবং এটি lastRSSI
এ সেট করুন পরিবর্তনশীল।
সামগ্রিকভাবে, আপনার পরিবর্তনগুলি এইরকম দেখতে হবে:
...
// Print out the UUID we're looking for
if( uuids[i].shorted() == TILE_UUID ) {
Log.trace("UUID: %x", uuids[i].shorted());
// If we're in learning mode. Save to EEprom
if( isLearningModeOn() ) {
searchAddress = scanResult->address;
EEPROM.put(TILE_EEPROM_ADDRESS, searchAddress);
setLearningModeOff();
}
// Save info
lastSeen = millis();
lastRSSI = scanResult->rssi;
// Stop scanning
BLE.stopScanning();
return;
}
এই ফাংশনের আগে, আমরা আমাদের searchAddress
এর সাথে মেলে না এমন ডিভাইসগুলিকে ফিল্টার করতে পারি . if( uuids[i].shorted() == TILE_UUID )
এর আগে নিম্নলিখিত যোগ করুন :
// If device address doesn't match or we're not in "learning mode"
if( !(searchAddress == scanResult->address) && !isLearningModeOn() ) {
return;
}
এটি মেলে না এমন ডিভাইসগুলিকে এড়িয়ে যাবে৷ ঠিকানাটি মেলে বা আমরা "লার্নিং মোডে" থাকলেই এটি এগিয়ে যাবে৷
৷
এখন, আমাদের searchAddress
লোড করার জন্য স্টার্টআপে, আমাদের এটি ফ্ল্যাশ থেকে লোড করতে হবে। এই লাইনটি আপনার setup():
এ যোগ করুন
EEPROM.get(TILE_EEPROM_ADDRESS, searchAddress);
তারপরে, ঠিকানাটি বৈধ কিনা তা নিশ্চিত করতে পরীক্ষা করুন। সমস্ত বাইট 0xFF
হলে এটি বৈধ হবে না :
// Warning about address
if( searchAddress == BleAddress("ff:ff:ff:ff:ff:ff") ) {
Log.warn("Place this board into learning mode");
Log.warn("and keep your Tile near by.");
}
আমাদের আর্গনকে আমাদের টাইলের ঠিকানা "শিক্ষা" দিতে সক্ষম হওয়া উচিত। আসুন এটি পরীক্ষা করে দেখি!
এটি পরীক্ষা করুন৷
৷এখন যদি আমরা অ্যাপটি কম্পাইল করে রান করি, লক্ষ্য করুন কিভাবে আর কোন লগ আউটপুট নেই? আমাদের পার্টিকেল ডিভাইসে টাইল ঠিকানাটি "শিক্ষা" দিতে হবে। সুতরাং, মোড বোতাম টিপুন। নীল LED চালু করা উচিত।
একবার আপনার টাইল পাওয়া গেলে LED বন্ধ হয়ে যাবে এবং আপনি কমান্ড লাইনে কিছু আউটপুট দেখতে পাবেন। আমরা আগে যা দেখেছি তার অনুরূপ:
0000006296 [app] TRACE: MAC: D7:E7:FE:0C:A5:C0
0000006298 [app] TRACE: RSSI: -60Bm
0000006299 [app] TRACE: UUID: feed
ডিভাইসটি স্মৃতিতে প্রতিশ্রুতিবদ্ধ!
রিসেট করার পরেও এটি সংরক্ষিত আছে কিনা তাও আপনি পরীক্ষা করতে পারেন। রিসেট টিপুন বোতাম এবং উপরের মত একই আউটপুট জন্য চেক করুন। যদি এটি প্রদর্শিত হয়, আমরা এখনও ভাল!
ক্লাউড আপডেট করুন
৷
অবশেষে checkTileStateChanged
নামে একটি ফাংশন সেট আপ করা যাক . আমরা নিয়মিত বিরতিতে টাইলের অবস্থার পরিবর্তনগুলি পরীক্ষা করতে এটি ব্যবহার করব৷
bool checkTileStateChanged( TilePresenceType *presence ) {
}
এই ফাংশনের মূল উদ্দেশ্য হল lastSeen
তুলনা করা "টাইমআউট" সময়কাল সহ পরিবর্তনশীল। আমাদের ক্ষেত্রে, আমাদের সময়সীমা হল TILE_NOT_HERE_MS
যা সেট করা উচিত
#define TILE_NOT_HERE_MS 30000
আপনার প্রোগ্রামের শীর্ষের কাছে। এছাড়াও আরো দুটি শর্ত আছে. একটি যেখানে lastSeen
0 এর সমান। এটি সাধারণত কারণ অ্যাপটি স্টার্টআপের পরে এখনও টাইল খুঁজে পায়নি।
শেষ কেস হবে যদি ডিভাইসটি দেখা হয়ে থাকে এবং lastSeen
0 নয়। তাই checkTileStateChanged
এর মধ্যে সবকিছু একসাথে করা যাক।
// Check to see if it's here.
if( millis() > lastSeen+TILE_NOT_HERE_MS ) {
} else if ( lastSeen == 0 ) {
} else {
}
return false;
এখন আমরা শুধুমাত্র এই ফাংশনটি সত্যে ফিরে আসতে চাই যদি অবস্থা পরিবর্তিত হয় . তাই আমাদের TilePresenceType
এর সুবিধা নিতে হবে চুক্তিতে নির্দেশক।
TilePresenceType
কেবলমাত্র সমস্ত সম্ভাব্য রাজ্যের একটি গণনা। আপনি এটিকে আপনার ফাইলের উপরেও আটকে রাখতে পারেন। এটি এখানে:
typedef enum {
PresenceUnknown,
Here,
NotHere
} TilePresenceType;
আপনার একটি গ্লোবাল ভেরিয়েবলেরও প্রয়োজন হবে যা আমরা ফাংশনে পাস করতে পারি। আপনার ফাইলের উপরেও এটি সেট করুন:
// Default status
TilePresenceType present = PresenceUnknown;
এখন, আমরা প্রতিটি পর্যায়ে তুলনা করতে পারি। এটা কি মানদণ্ড পূরণ করে? রাষ্ট্র কি গত এক থেকে ভিন্ন? যদি তাই হয়, সত্য ফিরে.
মনে রাখবেন, আমরা presence
সেট করতে চাই নতুন আপডেট করা মান পর্যন্ত। তাই প্রতিটি শর্ত উপস্থিতি মান আপডেট করা উচিত. যেমন:
*presence = NotHere;
সম্পূর্ণরূপে ফ্লাশ আউট ফাংশনটি কেমন দেখায় তা এখানে:
bool checkTileStateChanged( TilePresenceType *presence ) {
// Check to see if it's here.
if( millis() > lastSeen+TILE_NOT_HERE_MS ) {
if( *presence != NotHere ) {
*presence = NotHere;
Log.trace("not here!");
return true;
}
// Case if we've just started up
} else if ( lastSeen == 0 ) {
if( *presence != PresenceUnknown ) {
*presence = PresenceUnknown;
Log.trace("unknown!");
return true;
}
// Case if lastSeen is < TILE_NOT_HERE_MS
} else {
if( *presence != Here ) {
*presence = Here;
Log.trace("here!");
return true;
}
}
return false;
}
আমরা এখন Ble.scan()
শুরু করতে টাইমারের নীচে প্রধান লুপে এই ফাংশনটি ব্যবহার করতে পারি . আমরা একটি JSON পেলোড পাঠাতে এটি ব্যবহার করতে পারি। এই ক্ষেত্রে আমরা গুরুত্বপূর্ণ তথ্য যেমন ব্লুটুথ ঠিকানা, lastSeen
অন্তর্ভুক্ত করব৷ ডেটা, lastRSSI
ডেটা এবং একটি বার্তা৷
// If we have a change
if( checkTileStateChanged(&present) ) {
}
আমরা char
এর একটি অ্যারে ব্যবহার করব একটি স্ট্রিং বিন্যাসে আমাদের ঠিকানা পেতে. আপনি একসাথে চেইন করতে পারেন toString()
toCharArray
সহ আমাদের যা প্রয়োজন তা পেতে।
// Get the address string
char address[18];
searchAddress.toString().toCharArray(address,sizeof(address));
একটি উদাহরণ পেলোড স্ট্রিং এইরকম কিছু দেখতে পারে:
// Create payload
status = String::format("{\"address\":\"%s\",\"lastSeen\":%d,\"lastRSSI\":%i,\"status\":\"%s\"}",
address, lastSeen, lastRSSI, messages[present]);
status
ফাইলের উপরের অংশে সংজ্ঞায়িত একটি স্ট্রিং:
// The payload going to the cloud
String status;
আপনি লক্ষ্য করেছেন যে messages
নামে একটি পরিবর্তনশীলও রয়েছে . এটি একটি স্ট্যাটিক কনস্ট অ্যারে স্ট্রিং। সেগুলি TilePresenceType
থেকে মানগুলির সাথে ম্যাপ করা হয়েছে৷ . এটি দেখতে কেমন তা এখানে রয়েছে
const char * messages[] {
"unknown",
"here",
"not here"
};
এইভাবে PresenceUnknown
"unknown"
এর সাথে মেলে , Here
"here"
এর সাথে মেলে , ইত্যাদি। এটি একটি enum-এর সাথে একটি স্ট্রিং যুক্ত করার একটি সস্তা সহজ উপায়।
অবশেষে আমরা প্রকাশ এবং প্রক্রিয়া করব. এটি আমাদের অবিলম্বে আপডেট পাঠাতে অনুমতি দেয়৷
৷// Publish the RSSI and Device Info
Particle.publish("status", status, PRIVATE, WITH_ACK);
// Process the publish event immediately
Particle.process();
সামগ্রিক ফাংশন শেষ পর্যন্ত এই মত কিছু দেখতে হবে:
// If we have a change
if( checkTileStateChanged(&present) ) {
// Get the address string
char address[18];
searchAddress.toString().toCharArray(address,sizeof(address));
// Create payload
status = String::format("{\"address\":\"%s\",\"lastSeen\":%d,\"lastRSSI\":%i,\"status\":\"%s\"}",
address, lastSeen, lastRSSI, messages[present]);
// Publish the RSSI and Device Info
Particle.publish("status", status, PRIVATE, WITH_ACK);
// Process the publish event immediately
Particle.process();
}
এখন, এটা পরীক্ষা করা যাক!
এটি পরীক্ষা করা হচ্ছে!
৷পার্টিকেল ওয়ার্কবেঞ্চ ছাড়া ইভেন্ট ছাড়াই আমাদের প্রকাশনা ইভেন্টগুলি ঘটছে তা নিশ্চিত করার জন্য আমরা পরীক্ষা করতে পারি। ভিউ → টার্মিনাল এ গিয়ে একটি নতুন টার্মিনাল খুলুন৷ তারপর নিম্নলিখিত কমান্ড ব্যবহার করুন:
particle subscribe --device <device_name> <event_name>
<device_name>
প্রতিস্থাপন করুন আপনার ডিভাইসের নাম বা আইডি সহ।
<event_name>
প্রতিস্থাপন করুন অনুষ্ঠানের নামের সাথে। আমাদের ক্ষেত্রে এটি status
.
তারপর আপনি ব্যাটারি অপসারণ এবং "এখানে নয়" সতর্কতার জন্য অপেক্ষা করে এটি সব পরীক্ষা করতে পারেন। ব্যাটারি আবার প্লাগ ইন করুন এবং আপনার একটি "এখানে" সতর্কতা পাওয়া উচিত৷
৷এখানে আউটপুটের একটি উদাহরণ
> particle subscribe --device hamster_turkey status
Subscribing to "status" from hamster_turkey's stream
Listening to: /v1/devices/hamster_turkey/events/status
{"name":"status","data":"{\"address\":\"C0:A5:0C:FE:E7:D7\",\"lastSeen\":40154002,\"lastRSSI\":-82,\"status\":\"not here\"}","ttl":60,"published_at":"2019-09-07T02:29:42.232Z","coreid":"e00fce68d36c42ef433428eb"}
{"name":"status","data":"{\"address\":\"C0:A5:0C:FE:E7:D7\",\"lastSeen\":40193547,\"lastRSSI\":-83,\"status\":\"here\"}","ttl":60,"published_at":"2019-09-07T02:29:50.352Z","coreid":"e00fce68d36c42ef433428eb"}
ওয়েবহুক কনফিগার করা
এই টিউটোরিয়ালের শেষ অংশে আমরা একটি ওয়েবহুক ব্যবহার করে পুশ নোটিফিকেশন সেট আপ করব। যেমন আগে উল্লেখ করা হয়েছে, আমরা আপনার পছন্দের ডিভাইসে (গুলি) পুশ বিজ্ঞপ্তি পাঠাতে Pushover এবং তাদের সুবিধাজনক API ব্যবহার করব৷
Pushover ব্যবহার করার জন্য একটি চমত্কারভাবে সহজ API আছে। তাদের অ্যাপ্লিকেশন হল একটি সুইস আর্মি ছুরি যেখানে আপনি পুশ বিজ্ঞপ্তি পাঠানোর জন্য কোনো অ্যাপ কোড করতে চান না।
আপনাকে প্রথমে যে জিনিসটি নোট করতে হবে তা হল আপনার ব্যবহারকারী কী৷৷ আপনি Pushover লগ ইন করে এটি পেতে পারেন. দ্রষ্টব্য:আপনার যদি আগে থেকে না থাকে তবে আপনাকে প্রথমে একটি অ্যাকাউন্ট সেট আপ করতে হবে৷
এটি দেখতে এইরকম কিছু হওয়া উচিত:
আপনি যদি লগ ইন করে থাকেন এবং এই পৃষ্ঠাটি দেখতে না পান, তাহলে পুশওভার লোগোতে ক্লিক করুন এবং এটি আপনাকে ফিরিয়ে আনতে হবে।
এরপরে আমরা একটি অ্যাপ্লিকেশন তৈরি করতে চাই। অ্যাপস এবং প্লাগইন-এ ক্লিক করুন পর্দার শীর্ষে।
তারপরে আপনাকে একটি নতুন অ্যাপ্লিকেশন তৈরি করুন ক্লিক করতে হবে৷ এটি আমাদের একটি API টোকেন পেতে অনুমতি দেবে যেটি পার্টিকেল ওয়েবহুক সেটআপে প্রয়োজন হবে।
আপনি উপযুক্ত দেখতে একটি নাম সেট করুন. আপনি যদি একটি অনুস্মারক চান তাহলে বিবরণ পূরণ করুন. বক্সে ক্লিক করুন এবং তারপর অ্যাপ্লিকেশন তৈরি করুন ক্লিক করুন
আপনি পরবর্তী পৃষ্ঠায় যেতে হবে. API টোকেন/কী কপি করুন এবং সংরক্ষণ করুন আমাদের এটিও কয়েক ধাপে প্রয়োজন হবে।
এখন, ওয়েবহুক সেটআপ করা যাক। https://console.particle.io-এ যান এবং একটি নতুন ইন্টিগ্রেশন তৈরি করুন৷
৷আমরা ইভেন্টের নাম সেট করব স্থিতিতে .
URL https://api.pushover.net/1/messages.json-এ
এছাড়াও, আপনি যদি একটি নির্দিষ্ট ডিভাইস দ্বারা ফিল্টার করতে চান তবে নিশ্চিত করুন যে আপনি এটি ডিভাইস ড্রপডাউনে নির্বাচন করেছেন৷
উন্নত সেটিংসের অধীনে আমরা কয়েকটি ক্ষেত্র সেট করে শেষ করব।
নিম্নলিখিত ক্ষেত্রগুলি তৈরি করুন:টোকেন, ব্যবহারকারী , শিরোনাম , এবং বার্তা . তারপর API টোকেন-এ টোকেন সেট করুন আমরা আগে পেয়েছি। ব্যবহারকারী কী এর জন্যও একই কাজ করুন
শিরোনাম আপনার বার্তার শিরোনাম হিসাবে প্রদর্শিত হবে. আপনার জন্য যা কিছু বোধগম্য হয় তা করুন৷
আপনি বার্তা সেট করতে পারেন৷ The Tile is currently {{{status}}}. RSSI: {{{lastRSSI}}}
হিসাবে .
আমরা এখানে গোঁফের টেমপ্লেট ব্যবহার করছি। তারা আপনাকে প্রকাশিত পেলোডে ডেটা ব্যবহার করার অনুমতি দেয় এবং আপনার পছন্দ অনুসারে এটিকে পুনরায় ফর্ম্যাট করতে দেয়। আমাদের ক্ষেত্রে, আমরা সেগুলিকে "শূন্যস্থানগুলি পূরণ করতে" ব্যবহার করছি। বার্তা একবার প্রক্রিয়া করা হলে এরকম কিছু দেখাবে:
The Tile is currently here. RSSI: -77
একটি পার্শ্ব নোট হিসাবে, আমি আমার গাইডে এই টেমপ্লেটগুলি সম্পর্কে আরও কথা বলব। তাই এর জন্য সাথে থাকুন!
এটি পরীক্ষা করুন
৷একবার আপনার ইন্টিগ্রেশন হয়ে গেলে, আমরা আগের ধাপে যা করেছি তা আপনি পরীক্ষা করতে পারেন। ব্যাটারি সরান, এবং "এখানে নয়" বার্তার জন্য অপেক্ষা করুন। এটিকে আবার রাখুন এবং "এখানে" বার্তার জন্য অপেক্ষা করুন৷
৷এটি একটি iPhone এ কেমন দেখাবে তা এখানে:
আপনি দেখতে পারেন, আমি এটি একটি গুচ্ছ পরীক্ষা! ?
আপনি যদি এটি এতদূর তৈরি করে থাকেন এবং সবকিছুই কাজ করে, দুর্দান্ত কাজ। আপনার বাড়ি, অফিস বা যেখানেই হোক না কেন আপনার কাছে এখন একটি টাইল ট্র্যাকার রয়েছে৷
কোড
এই উদাহরণের জন্য সমাপ্ত কোড খুঁজছেন? আমিও হতাম! এটি Github-এ হোস্ট করা হয়েছে এবং এখানে উপলব্ধ৷
৷উপসংহার
আপনি কল্পনা করতে পারেন, এই নিবন্ধে ব্যবহৃত কৌশল এবং প্রযুক্তিগুলি বিভিন্ন উপায়ে ব্যবহার করা যেতে পারে। চলুন সংক্ষিপ্ত করা যাক কিছু মূল বিষয় তুলে ধরা হল:
- ব্লুটুথ সেন্ট্রাল ব্যবহার করে একটি অফ-দ্য-শেল্ফ টাইল ডিভাইসের জন্য স্ক্যান এবং সনাক্ত করা
- EEPROM-এ টাইল সনাক্তকারী তথ্য সংরক্ষণ করা। এইভাবে এটি স্টার্টআপে পুনরুদ্ধার করা যেতে পারে।
- আমাদের পরিচিত
Particle.publish
ব্যবহার করে ক্লাউডে আপডেট পুশ করতে। - রাজ্য পরিবর্তনের উপর পুশ বিজ্ঞপ্তি তৈরি করতে একটি পার্টিকেল ইন্টিগ্রেশন ওয়েবহুক ব্যবহার করে৷
এখন আপনার কাছে এটি সব কাজ করে, এটিকে প্রসারিত করুন, এটি হ্যাক করুন এবং এটিকে আপনার করুন৷ ওহ এবং শেয়ার করতে ভুলবেন না! আমি আপনার কাছ থেকে শুনতে চাই. [email protected]
এই পোস্ট পছন্দ? নীচের শেয়ার লিঙ্কগুলির একটিতে ক্লিক করুন এবং বিশ্বের সাথে শেয়ার করুন৷ :)
এটি আমার ব্লগ থেকে একটি ক্রস পোস্ট। আপনি এখানে আসলটি দেখতে পারেন৷৷
আরো শিখতে আগ্রহী? আমি পার্টিকেল প্ল্যাটফর্ম থেকে কীভাবে সবচেয়ে বেশি সুবিধা পেতে পারি সে সম্পর্কে একটি নির্দেশিকা লিখছি। এখানে এটি সম্পর্কে আরও জানুন।