דון בפרויקט שלך
MicrocosmWorksחדשנות ותכנון קוסמוס דיגיטלי
אודותצור קשר
MicrocosmWorksמחדשים ומתכננים קוסמוס דיגיטלי

מספקים פתרונות IT חשובים. אנו נלהבים מטכנולוגיה, אבטחה ועוזרים לעסקים לצמוח באמצעות תשתית IT אמינה וחדשנית.

hello@microcosmworks.com
+91 7011868196
New Delhi, India

פתרונות

בנייההנדסת מוצרי AIהנדסת מוצרי SaaSפיתוח תוכנה מותאמת אישית
מודרניזציהמודרניזציה של תוכנהמודרניזציה של AIמודרניזציה של אפליקציות ענן
הרחבהמערכות Backend ומבוזרותהנדסת ביצועי ענןהנדסת אמינות וביצועיםתשתית AI
הגדלהצוותי הנדסת מוצר
כל הפתרונותפיתוח סוכני AIפלטפורמת וידאו AIאפליקציות בריאות וכושר

שירותים

ייעוץ דיגיטליתשתית ענןפיתוח SaaSפיתוח AIטכנולוגיית וידאו
פיתוח ERPהתאמה אישית של Zohoפיתוח Odooאינטגרציה של Salesforceפיתוח CRM מותאם אישית
אינטגרציה של QuickBooksפתרונות IoTפיתוח בלוקצ'יין
ייעוץ סייברתמיכה טכנית - L3

מרכז צמיחה AI

מרכז AIחדשנות סטארטאפמאיץ ארגוני

משאבים

תובנותמדריכי תעשייהתוכניות מקרה שימושתבניות ארכיטקטורהמחקרי מקרה

חברה

אודותינוצור קשרדון בפרויקט שלךהעבודה שלנו

© 2026 MicrocosmWorks. כל הזכויות שמורות.

מדיניות פרטיותתנאי שירות
חזרה לתובנות
IoT Development

בניית אפליקציית מתקן מחובר

בניית אפליקציה מובייל המתחברת למכשיר מתקן מחובר ושולטת בו באמצעות BLE.

Mayank Joshi.webpMayank Chandra Joshi
•
September 7, 2026
•
עודכן October 3, 2026
•
6 min read
ChatGPT Image Sep 7, 2026, 12_49_11 PM (1).webp
6 min read

מרבית אפליקציות הלוויה הן שלטים דקים מבוססי BLE: לחיצה על כפתור, כתיבת ערך, וזהו. מתקן אינו יכול להיות כה דק – מתן מנה הוא אירוע בריאותי שחייב להיות מתועד בדיוק פעם אחת, המכשיר מדבר פרוטוקול בינארי מותאם אישית במקום פרופיל GATT סטנדרטי, ו"אל תחמיץ מנה" אינו יכול להיות תלוי בכך שהטלפון יהיה פעיל. כך בנינו את הנתיב מלחיצה למצב עמיד וניתן להתאמה, כחלק מעבודת wellness & fitness app development שלנו.

במבט מהיר

תחום: וולנס מחובר — מתן תוספים חכם

טכנולוגיות ליבה: React Native + Expo, react-native-ble-plx, Zustand, NestJS, MongoDB 8 (transactions)

יכולות מפתח: פרוטוקול פקודה/טלמטריה מותאם אישית של BLE, עדכוני קושחה SMP/CBOR, תיעוד מתן מנה טרנזקציוני, תזכורות מודעות אזורי זמן

סטטוס: נכנס לשלב 2 של הפיתוח

האתגר

הלקוח שלנו יצר מוצר וולנס מחובר: מכשיר המחלק תוספים, הנשלט מהטלפון. הדרך המקובלת לבניית אפליקציית הלוויה – והדרך שבה נבנות רובן – היא כשלט דק הכותב מאפיין וסומך על התוצאה. זה עובד עבור נורת חשמל, וכמעט ולא עובד כלל עבור מתקן.

ידענו זאת מראש, ולכן לא בנינו זאת בדרך זו. המגבלות של מודל השלט הדק הן מבניות, לא בעיות כוונון:

  • מתן מנה חייב להיות מתועד בדיוק פעם אחת. הוא מפחית מלאי פיזי, נספר כחלק ממנה יומית, ומזין נתוני אנליטיקה תזונתית. ספירה כפולה או כתיבה שאבדה משבשות את כל השלושה.
  • המכשיר מדבר פרוטוקול מותאם אישית, לא פרופיל. פקודות הן חבילות בינאריות ממוסגרות; אין מאפיין מוכן מהמדף שמשמעותו "תן טבליה אחת".
  • פקודות וטלמטריה אינן חולקות צורה. האפליקציה כותבת פקודות בינאריות קומפקטיות אך קוראת בחזרה טלמטריה בפורמט JSON (סוללה, טעינה, מזהה מחסנית, כמות מים) – על גבי מאפיינים שונים.
  • עדכוני קושחה עוברים באותו חיבור. המכשיר חייב להיות ניתן לשדרוג בשטח, דרך שירות ניהול נפרד, ללא כלי שני.
  • תזכורות אינן יכולות לחיות על המכשיר. "לא נטלת מנה היום" היא שאלה הנוגעת לאזורי זמן, היסטוריה, וביטול כפילויות – עניין של שרת, לא של טיימר בטלפון.

שורש הבעיה היה פשוט: מתן מנה אינו לחיצת כפתור, זו טרנזקציה – גם על גבי החיבור וגם במסד הנתונים. מודל שמתייחס לכך כאל כתיבה מסוג 'ירי ושיכחה' אינו יכול להבטיח אמינות באף אחד מהצדדים.

הפתרון שלנו

חילקנו אחריות כך שכל שכבה תעשה את מה שהיא הטובה ביותר בו: הטלפון מתזמן, המכשיר מבצע פרוטוקול מותאם אישית שהוגדר באמצעות IoT application development פרקטיקה, והענן הוא מערכת הרישום הטרנזקציונית – כאשר התזכורות מטופלות כולן בצד השרת.

ארכיטקטורה

  • React Native + Expo + Zustand — ה-BluetoothStore אחראי על חיבור ה-BLE, זרימת חלוקת המנה, והטלמטריה, המאוחסנים באופן עמיד ב-AsyncStorage.
  • react-native-ble-plx — סריקה, חיבור/חיבור מחדש, וקריאה/כתיבה של מאפיינים.
  • שכבת פקודות מותאמת אישית — בונה פקודות בינאריות ממוסגרות עבור המכשיר, ומשתמשת ב-CBOR על גבי שירות SMP לעדכוני קושחה.
  • NestJS API — נקודות קצה לחלוקת מנות ותזמון, הבנויות על אותה SaaS application development תשתית שאנו משתמשים בה במוצרי לקוחות שונים; רושמת כל חלוקת מנה בתוך טרנזקציית MongoDB.
  • MongoDB 8 (Mongoose) — מערכת הרישום, בתוספת אוספי סיכומים בזמן כתיבה שאותם קוראות מערכות אנליטיקה במורד הזרם.
  • NestJS Schedule crons + Expo push (queued via ActiveMQ/STOMP) — תזכורות מודעות אזורי זמן, שעברו דה-דופליקציה באמצעות יומני Mongo.
  • Sentry (mobile) — מעקב שגיאות ייצור באפליקציה.


architecture-ble-dispenser.webp

פרוטוקול תקשורת מותאם אישית

החלק הקשה בכל מוצר BLE הוא שהמכשיר אינו מדבר בשפה סטנדרטית. שלנו חושף שירות פקודות/טלמטריה ושירות קושחה (SMP) נפרד. האפליקציה מתחברת עם react-native-ble-plx, ואז נרשמת לטלמטריה – המגיעה בפורמט JSON על גבי מאפיין ההתראה (notify characteristic):

// BluetoothStore.ts — react-native-ble-plx + Zustand

const device = await bleManager.connectToDevice(deviceId, { autoConnect: true });

await device.discoverAllServicesAndCharacteristics();

// Telemetry: JSON over the notify characteristic (UUIDs are app-side constants).

bleManager.monitorCharacteristicForDevice(device.id, CH_SERVICE_UUID, TX_UUID, (_err, c) => {

  if (!c?.value) return;

  const t = JSON.parse(base64ToString(c.value));

  // { battery_percentage, charging_status, cartridge_id, water_qty, sequence, timestamp }

  set({ batteryPercentage: Number(t.battery_percentage), chargingStatus: t.charging_status });

});

 

מתן מנה הוא פקודה בינארית ממוסגרת קומפקטית – סמן התחלה, מזהה פקודה, אורך, בייט המחסנית, דגל קריאה/כתיבה, וסמן סיום – מקודדת ב-base64 ונכתבת למאפיין הפקודה. (מזהי ה-UUID וסמני המסגרת המילוליים צונזרו כאן.)

// Frame shape: [SOF] [CMD] [LEN] [DATA] [RW] [EOF]  — built by the command service.

const command = SNBCommandService.buildDispenseNutritionCommand(cartridgeId); // CMD = DISPENSE

await bleManager.writeCharacteristicWithResponseForDevice(

  device.id, CH_SERVICE_UUID, RX_UUID,

  SNBCommandService.uint8ArrayToBase64(command),
 
);

 

האפליקציה ממתינה לאישור מהמכשיר (היא מתאימה את מזהה הפקודה בחזרה מתוך מסגרת התגובה) לפני שהיא מתייחסת למתן המנה כאמיתי – ורק אז רושמת אותו בצד השרת. עדכוני קושחה משתמשים באותו חיבור אך בשפה שונה: מטענים חלקיקים של CBOR על גבי שירות ה-SMP.

מלחיצה לתיעוד

מתן מנה מאושר הופך למצב עמיד באמצעות נקודת קצה אחת – POST /dispense/tablet/:cartridgeId – הכותבת בתוך טרנזקציית MongoDB יחידה כך שששת ההשפעות כולן מתרחשות או שאף אחת מהן לא:


// dispense.service.ts — record exactly once, atomically

await session.withTransaction(async () => {

  await this.dispensed.create([{ cartridgeId, cartridgeModalId, dispensedBy: userId, dispensedAt }], { session });

  // write-time roll-up: totalDaysConsumed only increments on the first dose of the day

  await this.monthly.findOneAndUpdate(

    { userId, cartridgeModalId, month, year },

    { $inc: { totalTablets: 1, ...(firstDoseToday ? { totalDaysConsumed: 1 } : {}) } },

    { upsert: true, session },

  );

  await this.cartridge.updateOne({ cartridgeId }, { $inc: { tablets: -1 } }, { session });

  await this.dailyDose.updateOne({ userId, dateLocal }, { $inc: { tabletsTaken: 1 } }, { upsert: true, session });

  await this.notifications.cancelPending(userId, 'SUPPLEMENT_REMINDER', { session }); // mark IS_MISSED

});

 

טרנזקציה יחידה זו מעדכנת את יומן מתן המנות, את הסיכום החודשי, את המלאי הפיזי, את ספירת המנות היומית, ואת כל תזכורת ממתינה – וזו בדיוק הסיבה מדוע מתן מנה חייב להיות טרנזקציה, ולא כתיבה פשוטה.

תזכורות הן עניין של שרת

ברגע שמתן מנה עמיד, השאלות שטיימר בטלפון לא יכול היה לענות עליהן הופכות לשגרתיות – והן נענות על ידי משימות cron, לא על ידי האפליקציה:

  • האם משתמש זה נטל מנה היום, באזור הזמן שלו/שלה?
  • האם המחסנית ריקה (החלף) או שהמלאי ריק (הזמן מחדש), או שניהם (הפסקה)?
  • האם הם התרחקו מתחום בריאות שהיו רגילים לקחת?

שלושה @nestjs/schedule שירותים מטפלים באלה – תזכורת לוח זמנים/מנה, תזכורת מצב מחסנית, ותזכורת אי-פעילות חוצת תחומי בריאות. כל אחד מפענח את השעה המקומית של המשתמש באמצעות date-fns-tz, בודק ב-Mongo אם נטלו מנה היום, מבצע דה-דופליקציה מול אוסף יומנים, ומכניס הודעת דחיפה של Expo לתור באמצעות ActiveMQ. המכשיר לעולם אינו מעורב.

תוצאות

תכנון על בסיס "מתן מנה הוא טרנזקציה" במקום כתיבה דקה-מרחוק שינה את מה שהמערכת יכולה להבטיח:

  • רישום בדיוק פעם אחת. מתן מנה מעדכן את היומן, הסיכומים, המלאי, והמנה היומית באופן אטומי – ללא ספירות כפולות, ללא כתיבות חלקיות.
  • פרוטוקול מכשיר מתועד, כולל שדרוגים בשטח. פקודות וטלמטריה הן אזרחים ממדרגה ראשונה, ועדכוני קושחה נשלחים על גבי אותו חיבור באמצעות SMP/CBOR.
  • תזכורות נכונות, לא מקורבות. מודעות לאזורי זמן, מודעות להיסטוריה, ומונעות כפילויות בצד השרת – כך שהן מופעלות בין אם האפליקציה פתוחה ובין אם לאו.
  • אנליטיקה שאפשר לסמוך עליה. מכיוון שכל מתן מנה מסוכם בזמן הכתיבה, הנתונים המזינים את הגרפים והמעקב תמיד עקביים עם היומן.

ה-API, משימות ה-cron, ותור ההודעות המועברות פועלים על תשתית המנוהלת באמצעות cloud infrastructure services, כך שאותן הבטחות אמינות נשמרות ככל שצי המכשירים ובסיס המשתמשים גדלים.

מכלול טכנולוגי: React Native · Expo · TypeScript · react-native-ble-plx · Zustand · CBOR (SMP firmware) · NestJS · MongoDB 8 · Mongoose (transactions) · @nestjs/schedule · ActiveMQ / STOMP · Expo Server SDK · JWT · AWS S3 · AWS SES · Sentry (mobile)


קראו עוד מהצוות שלנו

1. Syncing Apple Health & Health Connect

2. חיפוש מתכונים מותאם אישית: אחזור שיודע מה כדאי לכם לאכול הלאה

3. אופטימיזציה של לוגו ערוץ עבור רזולוציות וידאו שונות

 

IoTBLEאפליקציה מוביילקישוריות
Mayank Joshi.webp

אודות המחבר

Mayank Chandra Joshi

AI & Cloud Solutions Expert at MicrocosmWorks

Building innovative AI-powered solutions and helping businesses transform through cutting-edge technology.

רוצים ללמוד עוד?

צרו קשר לדון כיצד נוכל לעזור ליישם פתרונות אלו עבור העסק שלכם.

צרו קשר

שאלות נפוצות

The app uses react-native-ble-plx to connect to the dispenser and communicate through its BLE characteristics. Dispense commands are built as framed binary packets containing fields such as the command ID, cartridge information, length, and read/write flag, while device telemetry is received separately as JSON.

A dispense is recorded only after the device acknowledges the corresponding command. The backend then records the confirmed dispense inside a MongoDB transaction, atomically updating the dispense log, stock, daily dose count, monthly roll-up, and pending reminder so the related state changes cannot be partially committed.

The dispenser uses a separate firmware management service based on the Simple Management Protocol (SMP). Firmware update data is transferred as chunked CBOR payloads over the same BLE connection, allowing the device to receive field updates without requiring a separate application or connection mechanism.

Dose reminders are handled server-side rather than by relying on a phone timer. NestJS scheduled services determine the user's local time, check MongoDB for the user's dosing history, de-duplicate reminder events, and queue Expo push notifications through ActiveMQ/STOMP. This allows reminders to be generated even when the mobile app is not open.

The system uses React Native, Expo, TypeScript, react-native-ble-plx, Zustand, NestJS, MongoDB 8 with Mongoose transactions, CBOR over SMP for firmware updates, @nestjs/schedule, ActiveMQ/STOMP, Expo Server SDK, JWT, AWS S3, AWS SES, and Sentry. Together, these components support BLE communication, transactional dispense recording, firmware management, reminders, storage, and mobile error tracking.

Comments (0)

Share your thoughts and join the conversation

Leave a Comment

Your email will not be published

No comments yet

Be the first to share your thoughts!