commit
c2f06740a1
@ -0,0 +1,284 @@
|
||||
# <div dir="rtl"> مقدمة لإنترنت الأشياء </div>
|
||||
|
||||

|
||||
|
||||
> <div dir="rtl"> خريطة من <a href="https://github.com/nitya">Nitya Narasimhan</a> </div>
|
||||
> <div dir="rtl"> اضغط على الصورة لتكبيرها </div>
|
||||
|
||||
## <div dir="rtl"> اختبار ما قبل المحاضرة </div>
|
||||
|
||||
[<div dir="rtl"> اختبار ما قبل المحاضرة </div>](https://brave-island-0b7c7f50f.azurestaticapps.net/quiz/1)
|
||||
|
||||
## <div dir="rtl"> المقدمة </div>
|
||||
|
||||
<div dir="rtl"> يغطي هذا الدرس بعض الموضوعات التمهيدية حول إنترنت الأشياء ، ويساعدك على إعداد أجهزتك. </div>
|
||||
|
||||
<div dir="rtl"> سنغطي في هذا الدرس: </div>
|
||||
|
||||
<div dir="rtl">
|
||||
|
||||
- [ ما هو انترنت الأشياء ](#what-is-the-internet-of-things)
|
||||
- [الأجهزة المتعلقة بانترنت الأشياء](#iot-devices)
|
||||
- [قم بإعداد جهازك](#set-up-your-device)
|
||||
- [تطبيقات انترنت الأشياء](#applications-of-iot)
|
||||
- [أمثلة على أجهزة إنترنت الأشياء التي قد تكون موجودة حولك](#examples-of-iot-devices-you-may-have-around-you)
|
||||
</div>
|
||||
|
||||
## <div dir="rtl"> ما هو "انترنت الأشياء"؟ </div>
|
||||
|
||||
<div dir="rtl"> مصطلح "إنترنت الأشياء" ابتكره
|
||||
<a href="https://wikipedia.org/wiki/KevinAshton">Kevin Ashton</a>
|
||||
في عام 1999 ، للإشارة إلى توصيل الإنترنت بالعالم المادي عبر أجهزة الاستشعار. منذ ذلك الحين ، تم استخدام المصطلح لوصف أي جهاز يتفاعل مع العالم المادي من حوله ، إما عن طريق جمع البيانات من أجهزة الاستشعار ، أو توفير تفاعلات في العالم الحقيقي عبر المشغلات (الأجهزة التي تقوم بشيء مثل تشغيل مفتاح أو إضاءة LED ) ، متصلة بشكل عام بأجهزة أخرى أو بالإنترنت. </div>
|
||||
|
||||
> <div dir="rtl"> المستشعرات تجمع المعلومات من العالم ، مثل قياس السرعة أو درجة الحرارة أو الموقع. </div>
|
||||
>
|
||||
> <div dir="rtl"> المشغلات تحول الإشارات الكهربائية إلى تفاعلات في العالم الحقيقي مثل تشغيل مفتاح أو تشغيل الأضواء أو إصدار أصوات أو إرسال إشارات تحكم إلى أجهزة أخرى ، على سبيل المثال لتشغيل مقبس طاقة. </div>
|
||||
|
||||
<div dir="rtl">إن إنترنت الأشياء كمجال تقني هو أكثر من مجرد أجهزة - فهو يشمل الخدمات المستندة إلى السحابة التي يمكنها معالجة بيانات المستشعر ، أو إرسال طلبات إلى المشغلات المتصلة بأجهزة إنترنت الأشياء. ويشمل أيضًا الأجهزة التي لا تحتوي على اتصال بالإنترنت أو لا تحتاج إليه ، وغالبًا ما يشار إليها باسم الأجهزة المتطورة. هذه هي الأجهزة التي يمكنها معالجة بيانات الاستشعار والاستجابة لها بنفسها ، وعادةً ما تستخدم نماذج الذكاء الاصطناعي المدربة في السحابة.</div>
|
||||
|
||||
<div dir="rtl">إنترنت الأشياء هو مجال تكنولوجي سريع النمو. تشير التقديرات إلى أنه بحلول نهاية عام 2020 ، تم نشر 30 مليار جهاز إنترنت الأشياء وتوصيلها بالإنترنت. بالنظر إلى المستقبل ، تشير التقديرات إلى أنه بحلول عام 2025 ، ستجمع أجهزة إنترنت الأشياء ما يقرب من 80 زيتابايت من البيانات ، أو 80 تريليون جيجابايت. هذا كثير من البيانات!</div>
|
||||
|
||||

|
||||
|
||||
<div dir="rtl">✅ قم بإجراء القليل من البحث: ما مقدار البيانات التي تم إنشاؤها بواسطة أجهزة إنترنت الأشياء المستخدمة بالفعل ، وكم يتم إهدارها؟ لماذا يتم تجاهل الكثير من البيانات؟ </div>
|
||||
|
||||
<div dir="rtl">
|
||||
هذه البيانات هي مفتاح نجاح إنترنت الأشياء. لكي تكون مطورًا ناجحًا لإنترنت الأشياء ، فأنت بحاجة إلى فهم البيانات التي تحتاج إلى جمعها ، وكيفية جمعها ، وكيفية اتخاذ القرارات بناءً عليها ، وكيفية استخدام هذه القرارات للتفاعل مع العالم المادي إذا لزم الأمر.</div>
|
||||
|
||||
## <div dir="rtl">الأجهزة المتعلقة بانترنت الأشياء</div>
|
||||
|
||||
<div dir="rtl">
|
||||
يرمز T في إنترنت الأشياء إلى الأشياء - الأجهزة التي تتفاعل مع العالم المادي من حولها إما عن طريق جمع البيانات من أجهزة الاستشعار ، أو توفير تفاعلات واقعية عبر المشغلات.
|
||||
|
||||
عادةً ما تكون الأجهزة المخصصة للإنتاج أو الاستخدام التجاري ، مثل أجهزة تتبع اللياقة البدنية للمستهلكين أو أجهزة التحكم في الآلات الصناعية ، مصنوعة خصيصًا. يستخدمون لوحات دوائر مخصصة ، وربما حتى معالجات مخصصة ، مصممة لتلبية احتياجات مهمة معينة ، سواء كانت صغيرة بما يكفي لتناسب معصمك ، أو متينة بما يكفي للعمل في درجات حرارة عالية ، أو ضغط مرتفع ، أو بيئة مصنع عالية الاهتزاز.
|
||||
|
||||
بصفتك مطورًا إما يتعلم عن إنترنت الأشياء أو يصنع نموذجًا أوليًا للجهاز ، فستحتاج إلى البدء بمجموعة أدوات التطوير. هذه أجهزة إنترنت الأشياء للأغراض العامة مصممة للمطورين لاستخدامها ، غالبًا مع ميزات لن تراها على جهاز إنتاج ، مثل مجموعة من المسامير الخارجية لتوصيل المستشعرات أو المشغلات بها ، أو الأجهزة لدعم التصحيح ، أو الموارد الإضافية التي سيضيف تكلفة غير ضرورية عند إجراء عملية تصنيع كبيرة.
|
||||
|
||||
تنقسم مجموعات المطورين هذه عادةً إلى فئتين - المتحكمات الدقيقة وأجهزة الكمبيوتر أحادية اللوحة. سيتم تقديم هذه هنا ، وسنتناول المزيد من التفاصيل في الدرس التالي.
|
||||
|
||||
>💁يمكن أيضًا اعتبار هاتفك جهاز إنترنت الأشياء للأغراض العامة ، مع أجهزة استشعار ومحركات مدمجة ، مع تطبيقات مختلفة تستخدم المستشعرات والمشغلات بطرق مختلفة مع خدمات سحابية مختلفة. يمكنك أيضًا العثور على بعض البرامج التعليمية لإنترنت الأشياء التي تستخدم تطبيق الهاتف كجهاز إنترنت الأشياء.
|
||||
|
||||
</div>
|
||||
|
||||
</br>
|
||||
|
||||
### <div dir="rtl">المتحكم الدقيق</div>
|
||||
|
||||
<div dir="rtl">
|
||||
المتحكم الدقيق (يشار إليه أيضًا باسم MCU ، اختصارًا لوحدة التحكم الدقيقة) هو جهاز كمبيوتر صغير يتكون من:
|
||||
|
||||
🧠 واحدة أو أكثر من وحدات المعالجة المركزية (CPUs) - "عقل" المتحكم الدقيق الذي يدير برنامجك
|
||||
|
||||
💾 الذاكرة (ذاكرة الوصول العشوائي وذاكرة البرنامج) - حيث يتم تخزين البرنامج والبيانات والمتغيرات الخاصة بك
|
||||
|
||||
🔌 اتصالات الإدخال / الإخراج القابلة للبرمجة (I / O) - للتحدث إلى الأجهزة الطرفية الخارجية (الأجهزة المتصلة) مثل المستشعرات والمشغلات
|
||||
|
||||
عادةً ما تكون وحدات التحكم الدقيقة أجهزة حوسبة منخفضة التكلفة ، حيث ينخفض متوسط أسعار الأجهزة المستخدمة في الأجهزة المخصصة إلى حوالي 0.50 دولار أمريكي ، وبعض الأجهزة رخيصة مثل 0.03 دولار أمريكي. يمكن أن تبدأ مجموعات المطورين بسعر منخفض يصل إلى 4 دولارات أمريكية ، مع ارتفاع التكاليف كلما أضفت المزيد من الميزات. <a href="https://www.seeedstudio.com/Wio-Terminal-p-4509.html">محطة Wio</a>, مجموعة مطور متحكم من <a href="https://www.seeedstudio.com">Seeed studios</a> تحتوي على أجهزة استشعار ومحركات واي فاي وشاشة تكلف حوالي 30 دولارًا أمريكيًا.
|
||||
</div>
|
||||
|
||||

|
||||
|
||||
> <div dir="rtl">💁 عند البحث في الإنترنت عن المتحكمات الدقيقة ، احذر من البحث عن المصطلح MCU لأن هذا سيعيد لك الكثير من النتائج ل Marvel السينمائي ، وليس للمتحكمات الدقيقة.</div>
|
||||
|
||||
<div dir="rtl">
|
||||
تم تصميم وحدات التحكم الدقيقة بحيث تتم برمجتها للقيام بعدد محدود من المهام المحددة للغاية ، بدلاً من أن تكون أجهزة كمبيوتر للأغراض العامة مثل أجهزة الكمبيوتر الشخصية أو أجهزة Mac. باستثناء سيناريوهات محددة للغاية ، لا يمكنك توصيل الشاشة ولوحة المفاتيح والماوس واستخدامها في مهام الأغراض العامة.
|
||||
|
||||
عادة ما تأتي مجموعات مطوري وحدات التحكم الدقيقة بأجهزة استشعار ومشغلات إضافية على متنها. تحتوي معظم اللوحات على واحد أو أكثر من مصابيح LED التي يمكنك برمجتها ، بالاضافة الى الأجهزة الأخرى مثل المقابس القياسية لإضافة المزيد من أجهزة الاستشعار أو المشغلات باستخدام أنظمة بيئية مختلفة للمصنعين ، أو أجهزة استشعار مدمجة (عادةً ما تكون الأكثر شيوعًا مثل مستشعرات درجة الحرارة). تحتوي بعض وحدات التحكم الدقيقة على اتصال لاسلكي مدمج مثل Bluetooth أو WiFi ، أو تحتوي على وحدات تحكم دقيقة إضافية على اللوحة لإضافة هذا الاتصال.
|
||||
</div>
|
||||
|
||||
> <div dir="rtl">💁 عادة ما يتم برمجة المتحكمات الدقيقة في C / C ++. </div>
|
||||
|
||||
### <div dir="rtl"> أجهزة كمبيوتر أحادية اللوحة</div>
|
||||
|
||||
<div dir="rtl"> الكمبيوتر أحادي اللوحة هو جهاز حوسبة صغير يحتوي على جميع عناصر الكمبيوتر الكامل الموجودة على لوحة صغيرة واحدة. هذه هي الأجهزة التي لها مواصفات قريبة من سطح المكتب أو الكمبيوتر المحمول أو جهاز Mac ، وتعمل بنظام تشغيل كامل ، ولكنها صغيرة ، وتستخدم طاقة أقل ، وأرخص بكثير.</div>
|
||||
|
||||

|
||||
|
||||
|
||||
***Raspberry Pi 4. Michael Henzler / [Wikimedia Commons](https://commons.wikimedia.org/wiki/Main_Page) / [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)***
|
||||
|
||||
|
||||
<div dir="rtl">
|
||||
يعد Raspberry Pi أحد أشهر أجهزة الكمبيوتر أحادية اللوحة.
|
||||
|
||||
مثل وحدة التحكم الدقيقة ، تحتوي أجهزة الكمبيوتر أحادية اللوحة على وحدة معالجة مركزية وذاكرة ودبابيس إدخال / إخراج ، ولكنها تحتوي على ميزات إضافية مثل شريحة رسومات للسماح لك بتوصيل الشاشات ومخرجات الصوت ومنافذ USB مثل كاميرات الويب أو وحدات التخزين الخارجية. يتم تخزين البرامج على بطاقات SD أو محركات أقراص ثابتة بالاضافة الى نظام التشغيل ، بدلاً من شريحة ذاكرة مدمجة في اللوحة.
|
||||
</div>
|
||||
|
||||
> <div dir="rtl">🎓 يمكنك التفكير في الكمبيوتر أحادي اللوحة كإصدار أصغر وأرخص من الكمبيوتر الشخصي أو جهاز Mac الذي تقرأ عليه ، مع إضافة دبابيس GPIO (إدخال / إخراج للأغراض العامة) للتفاعل مع المستشعرات والمحركات.</div>
|
||||
|
||||
|
||||
<div dir="rtl">أجهزة الكمبيوتر أحادية اللوحة هي أجهزة كمبيوتر كاملة الميزات ، لذا يمكن برمجتها بأي لغة. عادةً ما تتم برمجة أجهزة إنترنت الأشياء بلغة Python.</div>
|
||||
</br>
|
||||
|
||||
### <div dir="rtl"> اختيارات الأجهزة لبقية الدروس</div>
|
||||
|
||||
<div dir="rtl">تتضمن جميع الدروس اللاحقة مهام باستخدام جهاز إنترنت الأشياء للتفاعل مع العالم والتواصل مع السحابة. يدعم كل درس 3 خيارات للأجهزة - Arduino (باستخدام Seeed Studios Wio Terminal) ، أو كمبيوتر لوحة واحدة ، إما جهاز (Raspberry Pi 4) ، أو جهاز كمبيوتر افتراضي أحادي اللوحة يعمل على الكمبيوتر الشخصي أو جهاز Mac.</div>
|
||||
|
||||
يمكنك أن تقرأ عن الأجهزة اللازمة لإكمال جميع المهام في ملف [hardware guide](../../../../hardware.md)
|
||||
|
||||
> <div dir="rtl">💁 لا تحتاج إلى شراء أي جهاز إنترنت الأشياء لإكمال المهام ، يمكنك القيام بكل شيء باستخدام جهاز كمبيوتر افتراضي أحادي اللوحة. </div>
|
||||
|
||||
<div dir="rtl">تحديد الأجهزة التي تختارها متروك لك - يعتمد ذلك على ما لديك إما في المنزل أو في مدرستك ، ولغة البرمجة التي تعرفها أو تخطط لتعلمها. سيستخدم كلا النوعين من الأجهزة نفس نظام المستشعر البيئي ، لذلك إذا بدأت في مسار واحد ، يمكنك التغيير إلى الآخر دون الحاجة إلى استبدال معظم المجموعة. سيكون الكمبيوتر الافتراضي أحادي اللوحة مكافئًا للتعلم على Raspberry Pi ، حيث يمكن نقل معظم الشفرة إلى Pi إذا حصلت في النهاية على جهاز ومستشعرات.</div>
|
||||
|
||||
</br>
|
||||
|
||||
### <div dir="rtl"> مجموعة مطوري Arduino </div>
|
||||
|
||||
<div dir="rtl"> إذا كنت مهتمًا بتعلم تطوير وحدة التحكم الدقيقة ، فيمكنك إكمال المهام باستخدام جهاز Arduino. ستحتاج إلى فهم أساسي لبرمجة C / C ++ ، حيث أن الدروس ستعلم فقط الكود ذي صلة بإطار عمل Arduino ، وأجهزة الاستشعار والمشغلات المستخدمة ، والمكتبات التي تتفاعل مع السحابة. </div>
|
||||
|
||||
<div dir="rtl"> ستستخدم الواجبات <a href="https://www.seeedstudio.com/Wio-Terminal-p-4509.html">Visual Studio Code</a> مع <a href="https://www.seeedstudio.com/Wio-Terminal-p-4509.html">امتداد PlatformIO لتطوير وحدة التحكم الدقيقة</a>. يمكنك أيضًا استخدام Arduino IDE إذا كنت من ذوي الخبرة في هذه الأداة ، حيث لن يتم توفير الإرشادات.</div>
|
||||
|
||||
</br>
|
||||
|
||||
### <div dir="rtl"> مجموعة مطوري الكمبيوتر أحادية اللوحة </div>
|
||||
|
||||
<div dir="rtl">
|
||||
إذا كنت مهتمًا بتعلم تطوير إنترنت الأشياء باستخدام أجهزة كمبيوتر أحادية اللوحة ، فيمكنك إكمال المهام باستخدام Raspberry Pi ، أو جهاز افتراضي يعمل على جهاز الكمبيوتر أو جهاز Mac.
|
||||
|
||||
ستحتاج إلى فهم أساسي لبرمجة Python ، حيث ستعلم الدروس فقط التعليمات البرمجية ذات الصلة بالمستشعرات والمشغلات المستخدمة والمكتبات التي تتفاعل مع السحابة.
|
||||
</div>
|
||||
|
||||
> <div dir="rtl">💁 إذا كنت تريد تعلم البرمجة في Python ، فراجع سلسلتي الفيديو التاليين:
|
||||
>
|
||||
>* [بايثون للمبتدئين](https://channel9.msdn.com/Series/Intro-to-Python-Development?WT.mc_id=academic-17441-jabenn)
|
||||
> * [ المزيد من بايثون للمبتدئين ](https://channel9.msdn.com/Series/More-Python-for-Beginners?WT.mc_id=academic-7372-jabenn)
|
||||
</div>
|
||||
|
||||
<div dir="rtl">
|
||||
الواجبات ستستخدم <a href="https://www.seeedstudio.com/Wio-Terminal-p-4509.html">Visual Studio Code</a>
|
||||
|
||||
إذا كنت تستخدم Raspberry Pi ، فيمكنك إما تشغيل Pi الخاص بك باستخدام إصدار سطح المكتب الكامل من Raspberry Pi OS ، والقيام بكل الترميز مباشرة على Pi باستخدام <a href="https://code.visualstudio.com/docs/setup/raspberry-pi?WT.mc_id=academic-17441-jabenn">the Raspberry Pi OS version of VS Code</a> ، أو قم بتشغيل Pi من جهاز الكمبيوتر أو جهاز Mac باستخدام VS Code مع <a href="https://code.visualstudio.com/docs/remote/ssh?WT.mc_id=academic-17441-jabenn">Remote SSH extension</a> التي يتيح لك الاتصال بـ Pi الخاص بك وتحرير التعليمات البرمجية وتصحيحها وتشغيلها كما لو كنت تقوم بالتشفير عليها مباشرةً.
|
||||
|
||||
إذا كنت تستخدم خيار الجهاز الظاهري ، فستقوم بالتشفير مباشرة على جهاز الكمبيوتر الخاص بك. بدلاً من الوصول إلى المستشعرات والمشغلات ، ستستخدم أداة لمحاكاة هذا الجهاز لتوفير قيم أجهزة الاستشعار التي يمكنك تحديدها ، وإظهار نتائج المشغلات على الشاشة.
|
||||
</div>
|
||||
|
||||
### <div dir="rtl"> قم بإعداد جهازك </div>
|
||||
|
||||
<div dir="rtl"> قبل أن تبدأ في برمجة جهاز إنترنت الأشياء الخاص بك ، ستحتاج إلى إجراء قدر صغير من الإعداد. اتبع التعليمات ذات الصلة أدناه بناءً على الجهاز الذي ستستخدمه. </div>
|
||||
|
||||
> <div dir="rtl">💁 إذا لم يكن لديك جهاز بعد ، فارجع إلى </div>
|
||||
>
|
||||
>[hardware guide](../../../../hardware.md) للمساعدة في تحديد الجهاز الذي ستستخدمه والأجهزة الإضافية التي تحتاج إلى شرائها. لا تحتاج إلى شراء أجهزة ، حيث يمكن تشغيل جميع المشاريع على أجهزة افتراضية.
|
||||
|
||||
<div dir="rtl">
|
||||
تتضمن هذه التعليمات ارتباطات إلى مواقع ويب تابعة لجهات خارجية من منشئي الأجهزة أو الأدوات التي ستستخدمها. هذا للتأكد من أنك تستخدم دائمًا أحدث الإرشادات للأدوات والأجهزة المختلفة.
|
||||
|
||||
اعمل من خلال الدليل ذي الصلة لإعداد جهازك وإكمال مشروع "Hello World". ستكون هذه هي الخطوة الأولى في إنشاء ضوء ليلي لإنترنت الأشياء على الدروس الأربعة .
|
||||
|
||||
* [ وحدة Arduino - Wio ](../wio-terminal.md)
|
||||
* [كمبيوتر ذو لوحة واحدة - Raspberry Pi](../pi.md)
|
||||
* [كمبيوتر ذو لوحة واحدة - جهاز افتراضي](../virtual-device.md)
|
||||
</div>
|
||||
|
||||
### <div dir="rtl"> تطبيقات إنترنت الأشياء </div>
|
||||
|
||||
<div dir="rtl">يغطي إنترنت الأشياء مجموعة كبيرة من حالات الاستخدام عبر مجموعات قليلة:
|
||||
|
||||
* انترنت الاشياء المستهلك
|
||||
* إنترنت الأشياء التجاري
|
||||
* إنترنت الأشياء الصناعي
|
||||
* انترنت الاشياء البنية التحتية
|
||||
</div>
|
||||
|
||||
<div dir="rtl">✅ قم ببعض البحث: لكل مجال من المجالات الموضحة أدناه ، ابحث عن مثال ملموس واحد لم يرد في النص.</div>
|
||||
|
||||
### <div dir="rtl"> انترنت الاشياء المستهلك </div>
|
||||
|
||||
<div dir="rtl">
|
||||
يشير IoT للمستهلكين إلى أجهزة IoT التي سيشتريها المستهلكون ويستخدمونها في المنزل. بعض هذه الأجهزة مفيدة بشكل لا يصدق ، مثل مكبرات الصوت الذكية وأنظمة التدفئة الذكية والمكانس الكهربائية الآلية. البعض الآخر مشكوك فيه في فائدته ، مثل الصنابير التي يتم التحكم فيها بالصوت والتي تعني بعد ذلك أنه لا يمكنك إيقاف تشغيلها لأن التحكم الصوتي لا يمكنه سماع صوت المياه الجارية.
|
||||
|
||||
تعمل أجهزة إنترنت الأشياء للمستهلكين على تمكين الأشخاص من تحقيق المزيد في محيطهم ، وخاصة المليار شخص من ذوي الإعاقة. يمكن للمكانس الكهربائية الروبوتية توفير أرضيات نظيفة للأشخاص الذين يعانون من مشاكل في الحركة والذين لا يستطيعون تنظيف أنفسهم ، وتسمح الأفران التي يتم التحكم فيها بالصوت للأشخاص ذوي الرؤية المحدودة أو التحكم في المحرك بتسخين أفرانهم بصوتهم فقط ، ويمكن أن تسمح أجهزة المراقبة الصحية للمرضى بمراقبة الحالات المزمنة بأنفسهم بمزيد من الانتظام والمزيد من التحديثات التفصيلية عن ظروفهم. أصبحت هذه الأجهزة منتشرة في كل مكان حتى أن الأطفال الصغار يستخدمونها كجزء من حياتهم اليومية ، على سبيل المثال الطلاب الذين يقومون بالتعليم الافتراضي أثناء جائحة COVID يضبطون أجهزة ضبط الوقت على الأجهزة المنزلية الذكية لتتبع أعمالهم المدرسية أو أجهزة الإنذار لتذكيرهم باجتماعات الفصل القادمة.
|
||||
</div>
|
||||
|
||||
|
||||
<div dir="rtl">✅ ما هي أجهزة IoT الاستهلاكية التي لديك أو في منزلك؟ </div>
|
||||
|
||||
</br>
|
||||
|
||||
### <div dir="rtl">انترنت الأشياء التجاري </div>
|
||||
|
||||
<div dir="rtl">
|
||||
يغطي إنترنت الأشياء التجاري استخدام إنترنت الأشياء في مكان العمل. في مكتب ما ، قد يكون هناك أجهزة استشعار إشغال وكاشفات حركة لإدارة الإضاءة والتدفئة لإبقاء الأضواء والتدفئة فقط عند عدم الحاجة إليها ، مما يقلل التكلفة وانبعاثات الكربون. في المصنع ، يمكن لأجهزة إنترنت الأشياء مراقبة مخاطر السلامة مثل عدم ارتداء العمال للقبعات الصلبة أو الضوضاء التي وصلت إلى مستويات خطيرة. في البيع بالتجزئة ، يمكن لأجهزة إنترنت الأشياء قياس درجة حرارة التخزين البارد ، وتنبيه صاحب المتجر إذا كانت الثلاجة أو الفريزر خارج نطاق درجة الحرارة المطلوبة ، أو يمكنهم مراقبة العناصر الموجودة على الأرفف لتوجيه الموظفين لإعادة تعبئة المنتجات التي تم بيعها. تعتمد صناعة النقل أكثر فأكثر على إنترنت الأشياء لمراقبة مواقع المركبات ، وتتبع الأميال على الطريق لشحن مستخدمي الطريق ، وتتبع ساعات السائق وانقطاع الامتثال ، أو إخطار الموظفين عند اقتراب مركبة من المستودع للاستعداد للتحميل أو التفريغ.
|
||||
</div>
|
||||
|
||||
|
||||
<div dir="rtl">✅ ما هي أجهزة إنترنت الأشياء التجارية المتوفرة لديك في مدرستك أو مكان عملك؟ </div>
|
||||
|
||||
</br>
|
||||
|
||||
### <div dir="rtl">انترنت الأشياء الصناعي </div>
|
||||
|
||||
<div dir="rtl">
|
||||
إنترنت الأشياء الصناعي ، أو IIoT ، هو استخدام أجهزة إنترنت الأشياء للتحكم في الآلات وإدارتها على نطاق واسع. يغطي هذا مجموعة واسعة من حالات الاستخدام ، من المصانع إلى الزراعة الرقمية.
|
||||
|
||||
تستخدم المصانع أجهزة إنترنت الأشياء بعدة طرق مختلفة. يمكن مراقبة الماكينات بأجهزة استشعار متعددة لتتبع أشياء مثل درجة الحرارة والاهتزاز وسرعة الدوران. يمكن بعد ذلك مراقبة هذه البيانات للسماح للجهاز بالتوقف إذا خرج عن تفاوتات معينة - يعمل على درجة حرارة عالية جدًا ويتم إيقاف تشغيله على سبيل المثال. يمكن أيضًا جمع هذه البيانات وتحليلها بمرور الوقت لإجراء الصيانة التنبؤية ، حيث ستنظر نماذج الذكاء الاصطناعي في البيانات المؤدية إلى الفشل ، وتستخدم ذلك للتنبؤ بحالات الفشل الأخرى قبل حدوثها.
|
||||
|
||||
تعتبر الزراعة الرقمية مهمة إذا كان كوكب الأرض يريد إطعام العدد المتزايد من السكان ، خاصة بالنسبة لملياري شخص في 500 مليون أسرة تعيش على <a href="https://wikipedia.org/wiki/Subsistence_agriculture">زراعة الكفاف</a> يمكن أن تتراوح الزراعة الرقمية من عدد قليل من أجهزة الاستشعار بالدولار الواحد ، إلى الأجهزة التجارية الضخمة. يمكن للمزارع أن يبدأ بمراقبة درجات الحرارة واستخدام <a href="https://wikipedia.org/wiki/Growing_degree-day">أيام الدرجات المتزايدة</a> للتنبؤ بموعد جاهزية المحصول للحصاد. يمكنهم ربط مراقبة رطوبة التربة بأنظمة الري الآلية لمنح نباتاتهم القدر المطلوب من المياه ، ولكن ليس أكثر لضمان عدم جفاف محاصيلهم دون إهدار المياه. بل إن المزارعين يأخذون الأمر إلى أبعد من ذلك ويستخدمون الطائرات بدون طيار وبيانات الأقمار الصناعية والذكاء الاصطناعي لمراقبة نمو المحاصيل والأمراض وجودة التربة في مساحات شاسعة من الأراضي الزراعية
|
||||
</div>
|
||||
|
||||
<div dir="rtl">✅ ما هي أجهزة إنترنت الأشياء الأخرى التي يمكن أن تساعد المزارعين؟ </div>
|
||||
|
||||
### <div dir="rtl"> انترنت الاشياء البنية التحتية </div>
|
||||
|
||||
<div dir="rtl"> يقوم إنترنت الأشياء للبنية التحتية بمراقبة والتحكم في البنية التحتية المحلية والعالمية التي يستخدمها الناس كل يوم. </div>
|
||||
|
||||
<div dir="rtl"> <a href="https://wikipedia.org/wiki/Growing_degree-day">المدن الذكية </a> هي مناطق حضرية تستخدم أجهزة إنترنت الأشياء لجمع البيانات حول المدينة واستخدامها لتحسين كيفية إدارة المدينة. عادة ما يتم تشغيل هذه المدن بالتعاون بين الحكومات المحلية والأوساط الأكاديمية والشركات المحلية ، وتتبع وإدارة الأشياء التي تختلف من النقل إلى وقوف السيارات والتلوث. على سبيل المثال ، في كوبنهاغن ، الدنمارك ، يعد تلوث الهواء مهمًا للسكان المحليين ، لذلك يتم قياسه واستخدام البيانات لتوفير معلومات حول أنظف طرق ركوب الدراجات والركض. </div>
|
||||
|
||||
|
||||
<div dir="rtl"> <a href="https://wikipedia.org/wiki/Smart_grid">شبكات الكهرباء الذكية </a> تسمح بتحليلات أفضل للطلب على الطاقة من خلال جمع بيانات الاستخدام على مستوى المنازل الفردية. يمكن أن توجه هذه البيانات القرارات على مستوى الدولة بما في ذلك مكان بناء محطات طاقة جديدة ، وعلى المستوى الشخصي من خلال إعطاء المستخدمين رؤى حول مقدار الطاقة التي يستخدمونها ، وأوقات استخدامها ، وحتى اقتراحات حول كيفية تقليل التكاليف ، مثل لشحن السيارات الكهربائية في الليل. </div>
|
||||
|
||||
<div dir="rtl">✅ إذا كان بإمكانك إضافة أجهزة إنترنت الأشياء لقياس أي شيء تعيش فيه ، فماذا سيكون؟</div>
|
||||
|
||||
</br>
|
||||
|
||||
### <div dir="rtl">أمثلة على أجهزة إنترنت الأشياء التي قد تكون موجودة حولك </div>
|
||||
|
||||
<div dir="rtl">
|
||||
|
||||
ستندهش من عدد أجهزة إنترنت الأشياء الموجودة حولك. أكتب هذا من المنزل و لدي الأجهزة التالية متصلة بالإنترنت بميزات ذكية مثل التحكم في التطبيق أو التحكم الصوتي أو القدرة على إرسال البيانات إلي عبر هاتفي:
|
||||
|
||||
* مكبرات صوت ذكية متعددة
|
||||
* ثلاجة وغسالة صحون وفرن وميكروويف
|
||||
* مرقاب كهرباء الألواح الشمسية
|
||||
* المقابس الذكية
|
||||
* جرس باب بالفيديو وكاميرات مراقبة
|
||||
* ترموستات ذكي مع عدة مستشعرات ذكية للغرفة
|
||||
* فتحت باب المرآب
|
||||
* أنظمة الترفيه المنزلي وأجهزة التلفزيون ذات التحكم الصوتي
|
||||
* أضواء
|
||||
* أجهزة تتبع اللياقة البدنية والصحة
|
||||
|
||||
كل هذه الأنواع من الأجهزة لها مستشعرات و / أو مشغلات وتتحدث إلى الإنترنت. يمكنني معرفة ما إذا كان باب الكاراج الخاص بي مفتوحًا من هاتفي ، وأطلب من السماعة الذكية إغلاقها من أجلي. يمكنني حتى ضبطه على مؤقت ، لذلك إذا كان لا يزال مفتوحًا في الليل ، فسيتم إغلاقه تلقائيًا. عندما يرن جرس الباب ، يمكنني أن أرى من هاتفي من يوجد أينما كنت في العالم ، وأتحدث إليهم عبر مكبر صوت وميكروفون مدمجين في جرس الباب. يمكنني مراقبة الجلوكوز في الدم ومعدل ضربات القلب وأنماط النوم ، والبحث عن أنماط في البيانات لتحسين صحتي. يمكنني التحكم في الأضواء الخاصة بي عبر السحابة ، والجلوس في الظلام عندما ينقطع الاتصال بالإنترنت.
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
## <div dir="rtl">تحدي </div>
|
||||
|
||||
<div dir="rtl">ضع قائمة بأكبر عدد ممكن من أجهزة إنترنت الأشياء الموجودة في منزلك أو مدرستك أو مكان عملك - قد يكون هناك أكثر مما تعتقد! </div>
|
||||
|
||||
</br>
|
||||
|
||||
## <div dir="rtl">مسابقة ما بعد المحاضرة </div>
|
||||
|
||||
<div dir="rtl">
|
||||
<a href="https://brave-island-0b7c7f50f.azurestaticapps.net/quiz/2">مسابقة ما بعد المحاضرة </a> </div>
|
||||
|
||||
</br>
|
||||
|
||||
## <div dir="rtl">المراجعة والدراسة الذاتية </div>
|
||||
|
||||
<div dir="rtl"> اقرأ عن مزايا وإخفاقات مشروعات إنترنت الأشياء للمستهلكين. تحقق من المواقع الإخبارية بحثًا عن مقالات عن الأوقات التي حدث فيها خطأ ، مثل مشكلات الخصوصية أو مشكلات الأجهزة أو المشكلات الناجمة عن نقص الاتصال.
|
||||
|
||||
بعض الأمثلة:
|
||||
|
||||
* قم بالاطلاع على حساب التويتر لأمثلة جيدة على انترنت الاشياء المستهلك **[Internet of Sh*t](https://twitter.com/internetofshit)** *(profanity warning)*
|
||||
* [c|net - My Apple Watch saved my life: 5 people share their stories](https://www.cnet.com/news/apple-watch-lifesaving-health-features-read-5-peoples-stories/)
|
||||
* [c|net - ADT technician pleads guilty to spying on customer camera feeds for years](https://www.cnet.com/news/adt-home-security-technician-pleads-guilty-to-spying-on-customer-camera-feeds-for-years/) *(trigger warning - non-consensual voyeurism)*
|
||||
|
||||
### الواجب
|
||||
|
||||
[التحقيق في مشروع إنترنت الأشياء](assignment.ar.md)
|
||||
|
||||
</div>
|
||||
|
@ -0,0 +1,20 @@
|
||||
|
||||
<div dir="rtl">
|
||||
|
||||
# التحقيق في مشروع إنترنت الأشياء
|
||||
|
||||
## تعليمات
|
||||
|
||||
هناك العديد من مشاريع إنترنت الأشياء الكبيرة والصغيرة التي يتم طرحها على مستوى العالم ، من المزارع الذكية إلى المدن الذكية ، ومراقبة الرعاية الصحية ، والنقل ، أو استخدام الأماكن العامة.
|
||||
|
||||
ابحث في الويب عن تفاصيل المشروع الذي يثير اهتمامك ، ومن الأفضل أن يكون مشروعًا قريبًا من المكان الذي تعيش فيه. اشرح الجوانب الإيجابية والسلبية للمشروع ، مثل الفائدة التي تأتي منه ، وأي مشاكل يسببها وكيف يتم أخذ الخصوصية في الاعتبار.
|
||||
|
||||
## الموضوع
|
||||
|
||||
|
||||
| المعايير | نموذجي | كافية | يحتاج إلى تحسين |
|
||||
| -------- | --------- | -------- | ----------------- |
|
||||
| اشرح الإيجابيات والسلبيات | قدّم شرحاً واضحاً لأوجه الإيجابيات والسلبيات للمشروع | قدم شرحا مختصرا للجوانب الإيجابية والسلبية | لم يشرح الإيجابيات أو السلبيات |
|
||||
|
||||
|
||||
</div>
|
@ -0,0 +1,13 @@
|
||||
# একটি IoT প্রজেক্ট পর্যালোচনা
|
||||
|
||||
## নির্দেশাবলী
|
||||
|
||||
স্মার্ট ফার্ম থেকে শুরু করে স্মার্ট শহরগুলিতে, স্বাস্থ্যসেবা পর্যবেক্ষণ, পরিবহন এবং জনসাধারণের ব্যবহারের জন্য বিশ্বব্যাপী বড় এবং ছোট আকারের অনেক আইওটি প্রকল্প আসছে।
|
||||
|
||||
আপনার বসবাসের জায়গার আশেপাশের এমন কোন প্রকল্প থাকলে, সেটি সম্পর্কে ইন্টারনেটে সার্চ করুন। প্রজেক্টটির ইতিবাচক এবং নেতিবাচক দিকগুলো (যেমন: এটির কারণে কী কী সুবিধা হচ্ছে, কোন সমস্যা তৈরী করছে কিনা বা তথ্যের গোপনীয়তা সংক্রান্ত বিষয়গুলি কীভাবে দেখা হচ্ছে) ব্যখ্যা করুন।
|
||||
|
||||
## এসাইনমেন্ট মূল্যায়ন মানদন্ড
|
||||
|
||||
| ক্রাইটেরিয়া | দৃষ্টান্তমূলক ব্যখ্যা | পর্যাপ্ত ব্যখ্যা | আরো উন্নতির প্রয়োজন |
|
||||
| -------- | --------- | -------- | -----------------|
|
||||
| ইতিবাচক এবং নেতিবাচক দিকগুলোর ব্যখ্যা করুন | বিশদভাব ব্যখ্যা করা হয়েছে | সংক্ষিপ্ত ব্যখ্যা করা হয়েছে | ভালোভাবে ব্যখ্যা করা হয়নি |
|
@ -0,0 +1,16 @@
|
||||
<div dir="rtl">
|
||||
|
||||
# قارن بين المتحكمات الدقيقة وأجهزة الكمبيوتر أحادية اللوحة
|
||||
|
||||
## التعليمات
|
||||
|
||||
غطى هذا الدرس المتحكمات الدقيقة وأجهزة الكمبيوتر أحادية اللوحة. قم بإنشاء جدول لمقارنتها ، ولاحظ على الأقل سببين لاستخدام متحكم دقيق على جهاز كمبيوتر ذي لوحة واحدة ، وسببين على الأقل لاستخدام جهاز كمبيوتر من لوحة واحدة بدلاً من متحكم دقيق.
|
||||
|
||||
## نماذج
|
||||
|
||||
| معايير | نموذجي | مناسب | يحتاج الى تحسين |
|
||||
| -------- | --------- | -------- | ----------------- |
|
||||
| قم بإنشاء جدول يقارن المتحكمات الدقيقة بأجهزة الكمبيوتر أحادية اللوحة | إنشاء قائمة بالعناصر المتعددة للمقارنة والتباين بشكل صحيح | تم إنشاء قائمة تحتوي على عنصرين فقط | كان قادرًا على الخروج بعنصر واحد فقط ، أو لا توجد عناصر للمقارنة والتباين |
|
||||
| أسباب استخدام أحدهما على الآخر | كان قادرًا على تقديم سببين أو أكثر لاجهزة التحكم الدقيق ، وسببين أو أكثر لأجهزة الكمبيوتر ذات اللوحة الواحدة | كان قادرًا فقط على تقديم 1-2 سبب لمتحكم دقيق ، وسببين أو اكثر لجهاز كمبيوتر لوحة واحدة | لم يكن قادرًا على تقديم سبب واحد أو أكثر لمتحكم دقيق أو لجهاز كمبيوتر أحادي اللوحة |
|
||||
|
||||
<div>
|
@ -1,9 +1,12 @@
|
||||
#
|
||||
# Deploy your app
|
||||
|
||||
## Instructions
|
||||
|
||||
There are several ways that you can deploy your app so that you can share it with the world, including using GitHub pages or using one of many service providers. A really excellent way to do this is to use Azure Static Web Apps. In this assignment, build your web app and deploy it to the cloud by following [these instructions](https://github.com/Azure/static-web-apps-cli) or watching [these videos](https://www.youtube.com/watch?v=ADVGIXciYn8&list=PLlrxD0HtieHgMPeBaDQFx9yNuFxx6S1VG&index=3).
|
||||
A benefit of using Azure Static Web Apps is that you can hide any API keys in the portal, so take this opportunity to refactor your subscriptionKey as a variable and store it in the cloud.
|
||||
|
||||
## Rubric
|
||||
|
||||
| Criteria | Exemplary | Adequate | Needs Improvement |
|
||||
| -------- | --------- | -------- | ----------------- |
|
||||
| | | | |
|
||||
| -------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
|
||||
| | A working web app is presented in a documented GitHub repository with its subscriptionKey stored in the cloud and called via a variable | A working web app is presented in a documented GitHub repository but its subscriptionKey is not stored in the cloud | The web app contains bugs or does not work properly |
|
||||
|
@ -0,0 +1,46 @@
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<link rel="stylesheet" href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.css" type="text/css" />
|
||||
<script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.js"></script>
|
||||
|
||||
<script type='text/javascript'>
|
||||
|
||||
function init() {
|
||||
fetch("https://gpssensorjimb.blob.core.windows.net/gps-data/?restype=container&comp=list")
|
||||
.then(response => response.text())
|
||||
.then(str => new window.DOMParser().parseFromString(str, "text/xml"))
|
||||
.then(xml => {
|
||||
let blobList = Array.from(xml.querySelectorAll("Url")); //.getAttribute("Url");
|
||||
blobList.forEach(async blobUrl => {
|
||||
console.log(blobUrl);
|
||||
});
|
||||
})
|
||||
.then( response => {
|
||||
var map = new atlas.Map('myMap', {
|
||||
center: [-122.33, 47.6],
|
||||
zoom: 12,
|
||||
authOptions: {
|
||||
authType: "subscriptionKey",
|
||||
subscriptionKey: "<your-key>",
|
||||
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
#myMap {
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body onload="init()">
|
||||
<div id="myMap"></div>
|
||||
</body>
|
||||
|
||||
|
||||
|
||||
</html>
|
After Width: | Height: | Size: 571 KiB |
@ -1,7 +1,20 @@
|
||||
# Retail - using IoT to manage stock levels
|
||||
|
||||
The last stage for feed before it reaches consumers is retail - the markets, greengrocers, supermarkets and stores that sell produce to consumers. These stores want to ensure they have produce out on shelves for consumers to see and buy.
|
||||
|
||||
One of the most manual, time consuming tasks in food stores, especially in large supermarkets, is making sure the shelves are stocked. Checking individual shelves to ensure any gaps are filled with produce from store rooms.
|
||||
|
||||
IoT can help with this, using AI models running on IoT devices to count stock, using machine learning models that don't just classify images, but can detect individual objects and count them.
|
||||
|
||||
In these 2 lessons you'll learn how to train image-based AI models to count stock, and run these models on IoT devices.
|
||||
|
||||
> 💁 These lessons will use some cloud resources. If you don't complete all the lessons in this project, make sure you [Clean up your project](../clean-up.md).
|
||||
|
||||
## Topics
|
||||
|
||||
1. [Train a stock detector](./lessons/1-train-stock-detector/README.md)
|
||||
1. [Check stock from an IoT device](./lessons/2-check-stock-device/README.md)
|
||||
|
||||
## Credits
|
||||
|
||||
All the lessons were written with ♥️ by [Jim Bennett](https://GitHub.com/JimBobBennett)
|
||||
|
@ -0,0 +1,33 @@
|
||||
# Train a stock detector
|
||||
|
||||
Add a sketchnote if possible/appropriate
|
||||
|
||||

|
||||
|
||||
## Pre-lecture quiz
|
||||
|
||||
[Pre-lecture quiz](https://brave-island-0b7c7f50f.azurestaticapps.net/quiz/37)
|
||||
|
||||
## Introduction
|
||||
|
||||
In this lesson you will learn about
|
||||
|
||||
In this lesson we'll cover:
|
||||
|
||||
* [Thing 1](#thing-1)
|
||||
|
||||
## Thing 1
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Challenge
|
||||
|
||||
## Post-lecture quiz
|
||||
|
||||
[Post-lecture quiz](https://brave-island-0b7c7f50f.azurestaticapps.net/quiz/38)
|
||||
|
||||
## Review & Self Study
|
||||
|
||||
## Assignment
|
||||
|
||||
[](assignment.md)
|
@ -0,0 +1,9 @@
|
||||
#
|
||||
|
||||
## Instructions
|
||||
|
||||
## Rubric
|
||||
|
||||
| Criteria | Exemplary | Adequate | Needs Improvement |
|
||||
| -------- | --------- | -------- | ----------------- |
|
||||
| | | | |
|
@ -0,0 +1,33 @@
|
||||
# Check stock from an IoT device
|
||||
|
||||
Add a sketchnote if possible/appropriate
|
||||
|
||||

|
||||
|
||||
## Pre-lecture quiz
|
||||
|
||||
[Pre-lecture quiz](https://brave-island-0b7c7f50f.azurestaticapps.net/quiz/39)
|
||||
|
||||
## Introduction
|
||||
|
||||
In this lesson you will learn about
|
||||
|
||||
In this lesson we'll cover:
|
||||
|
||||
* [Thing 1](#thing-1)
|
||||
|
||||
## Thing 1
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Challenge
|
||||
|
||||
## Post-lecture quiz
|
||||
|
||||
[Post-lecture quiz](https://brave-island-0b7c7f50f.azurestaticapps.net/quiz/40)
|
||||
|
||||
## Review & Self Study
|
||||
|
||||
## Assignment
|
||||
|
||||
[](assignment.md)
|
@ -0,0 +1,9 @@
|
||||
#
|
||||
|
||||
## Instructions
|
||||
|
||||
## Rubric
|
||||
|
||||
| Criteria | Exemplary | Adequate | Needs Improvement |
|
||||
| -------- | --------- | -------- | ----------------- |
|
||||
| | | | |
|
@ -0,0 +1,9 @@
|
||||
# Dummy File
|
||||
|
||||
This file acts as a placeholder for the `translations` folder. <br>
|
||||
**Please remove this file after adding the first translation**
|
||||
|
||||
For the instructions, follow the directives in the [translations guide](https://github.com/microsoft/IoT-For-Beginners/blob/main/TRANSLATIONS.md) .
|
||||
|
||||
## THANK YOU
|
||||
We truly appreciate your efforts!
|
@ -1,9 +1,12 @@
|
||||
#
|
||||
# Cancel the timer
|
||||
|
||||
## Instructions
|
||||
|
||||
In the assignment for the last lesson, you added a cancel timer intent to LUIS. For this assignment you need to handle this intent in the serverless code, send a command to the IoT device, then cancel the timer.
|
||||
|
||||
## Rubric
|
||||
|
||||
| Criteria | Exemplary | Adequate | Needs Improvement |
|
||||
| -------- | --------- | -------- | ----------------- |
|
||||
| | | | |
|
||||
| Handle the intent in serverless code and send a command | Was able to handle the intent and send a command to the device | Was able to handle the intent but was unable to send the command to the device | Was unable to handle the intent |
|
||||
| Cancel the timer on the device | Was able to receive the command and cancel the timer | Was able to receive the command but not cancel the timer | Was unable to receive the command |
|
||||
|
@ -0,0 +1,15 @@
|
||||
{
|
||||
"version": "2.0",
|
||||
"logging": {
|
||||
"applicationInsights": {
|
||||
"samplingSettings": {
|
||||
"isEnabled": true,
|
||||
"excludedTypes": "Request"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extensionBundle": {
|
||||
"id": "Microsoft.Azure.Functions.ExtensionBundle",
|
||||
"version": "[2.*, 3.0.0)"
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"IsEncrypted": false,
|
||||
"Values": {
|
||||
"FUNCTIONS_WORKER_RUNTIME": "python",
|
||||
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
|
||||
"IOT_HUB_CONNECTION_STRING": "<connection string>",
|
||||
"LUIS_KEY": "<primary key>",
|
||||
"LUIS_ENDPOINT_URL": "<endpoint url>",
|
||||
"LUIS_APP_ID": "<app id>",
|
||||
"REGISTRY_MANAGER_CONNECTION_STRING": "<connection string>"
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
# Do not include azure-functions-worker as it may conflict with the Azure Functions platform
|
||||
|
||||
azure-functions
|
||||
azure-cognitiveservices-language-luis
|
@ -0,0 +1,60 @@
|
||||
from typing import List
|
||||
import logging
|
||||
|
||||
import azure.functions as func
|
||||
|
||||
import json
|
||||
import os
|
||||
from azure.cognitiveservices.language.luis.runtime import LUISRuntimeClient
|
||||
from msrest.authentication import CognitiveServicesCredentials
|
||||
|
||||
from azure.iot.hub import IoTHubRegistryManager
|
||||
from azure.iot.hub.models import CloudToDeviceMethod
|
||||
|
||||
def main(events: List[func.EventHubEvent]):
|
||||
luis_key = os.environ['LUIS_KEY']
|
||||
endpoint_url = os.environ['LUIS_ENDPOINT_URL']
|
||||
app_id = os.environ['LUIS_APP_ID']
|
||||
registry_manager_connection_string = os.environ['REGISTRY_MANAGER_CONNECTION_STRING']
|
||||
|
||||
credentials = CognitiveServicesCredentials(luis_key)
|
||||
client = LUISRuntimeClient(endpoint=endpoint_url, credentials=credentials)
|
||||
|
||||
for event in events:
|
||||
logging.info('Python EventHub trigger processed an event: %s',
|
||||
event.get_body().decode('utf-8'))
|
||||
|
||||
device_id = event.iothub_metadata['connection-device-id']
|
||||
|
||||
event_body = json.loads(event.get_body().decode('utf-8'))
|
||||
prediction_request = { 'query' : event_body['speech'] }
|
||||
|
||||
prediction_response = client.prediction.get_slot_prediction(app_id, 'Staging', prediction_request)
|
||||
|
||||
if prediction_response.prediction.top_intent == 'set timer':
|
||||
numbers = prediction_response.prediction.entities['number']
|
||||
time_units = prediction_response.prediction.entities['time unit']
|
||||
total_seconds = 0
|
||||
|
||||
for i in range(0, len(numbers)):
|
||||
number = numbers[i]
|
||||
time_unit = time_units[i][0]
|
||||
|
||||
if time_unit == 'minute':
|
||||
total_seconds += number * 60
|
||||
else:
|
||||
total_seconds += number
|
||||
|
||||
logging.info(f'Timer required for {total_seconds} seconds')
|
||||
|
||||
payload = {
|
||||
'seconds': total_seconds
|
||||
}
|
||||
direct_method = CloudToDeviceMethod(method_name='set-timer', payload=json.dumps(payload))
|
||||
|
||||
registry_manager_connection_string = os.environ['REGISTRY_MANAGER_CONNECTION_STRING']
|
||||
registry_manager = IoTHubRegistryManager(registry_manager_connection_string)
|
||||
|
||||
registry_manager.invoke_device_method(device_id, direct_method)
|
||||
|
||||
|
@ -0,0 +1,15 @@
|
||||
{
|
||||
"scriptFile": "__init__.py",
|
||||
"bindings": [
|
||||
{
|
||||
"type": "eventHubTrigger",
|
||||
"name": "events",
|
||||
"direction": "in",
|
||||
"eventHubName": "samples-workitems",
|
||||
"connection": "IOT_HUB_CONNECTION_STRING",
|
||||
"cardinality": "many",
|
||||
"consumerGroup": "$Default",
|
||||
"dataType": "binary"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,184 @@
|
||||
import io
|
||||
import json
|
||||
import pyaudio
|
||||
import requests
|
||||
import time
|
||||
import wave
|
||||
import threading
|
||||
|
||||
from azure.iot.device import IoTHubDeviceClient, Message, MethodResponse
|
||||
|
||||
from grove.factory import Factory
|
||||
button = Factory.getButton('GPIO-HIGH', 5)
|
||||
|
||||
audio = pyaudio.PyAudio()
|
||||
microphone_card_number = 1
|
||||
speaker_card_number = 1
|
||||
rate = 16000
|
||||
|
||||
def capture_audio():
|
||||
stream = audio.open(format = pyaudio.paInt16,
|
||||
rate = rate,
|
||||
channels = 1,
|
||||
input_device_index = microphone_card_number,
|
||||
input = True,
|
||||
frames_per_buffer = 4096)
|
||||
|
||||
frames = []
|
||||
|
||||
while button.is_pressed():
|
||||
frames.append(stream.read(4096))
|
||||
|
||||
stream.stop_stream()
|
||||
stream.close()
|
||||
|
||||
wav_buffer = io.BytesIO()
|
||||
with wave.open(wav_buffer, 'wb') as wavefile:
|
||||
wavefile.setnchannels(1)
|
||||
wavefile.setsampwidth(audio.get_sample_size(pyaudio.paInt16))
|
||||
wavefile.setframerate(rate)
|
||||
wavefile.writeframes(b''.join(frames))
|
||||
wav_buffer.seek(0)
|
||||
|
||||
return wav_buffer
|
||||
|
||||
speech_api_key = '<key>'
|
||||
location = '<location>'
|
||||
language = '<language>'
|
||||
connection_string = '<connection_string>'
|
||||
|
||||
device_client = IoTHubDeviceClient.create_from_connection_string(connection_string)
|
||||
|
||||
print('Connecting')
|
||||
device_client.connect()
|
||||
print('Connected')
|
||||
|
||||
def get_access_token():
|
||||
headers = {
|
||||
'Ocp-Apim-Subscription-Key': speech_api_key
|
||||
}
|
||||
|
||||
token_endpoint = f'https://{location}.api.cognitive.microsoft.com/sts/v1.0/issuetoken'
|
||||
response = requests.post(token_endpoint, headers=headers)
|
||||
return str(response.text)
|
||||
|
||||
def convert_speech_to_text(buffer):
|
||||
url = f'https://{location}.stt.speech.microsoft.com/speech/recognition/conversation/cognitiveservices/v1'
|
||||
|
||||
headers = {
|
||||
'Authorization': 'Bearer ' + get_access_token(),
|
||||
'Content-Type': f'audio/wav; codecs=audio/pcm; samplerate={rate}',
|
||||
'Accept': 'application/json;text/xml'
|
||||
}
|
||||
|
||||
params = {
|
||||
'language': language
|
||||
}
|
||||
|
||||
response = requests.post(url, headers=headers, params=params, data=buffer)
|
||||
response_json = json.loads(response.text)
|
||||
|
||||
if response_json['RecognitionStatus'] == 'Success':
|
||||
return response_json['DisplayText']
|
||||
else:
|
||||
return ''
|
||||
|
||||
def get_voice():
|
||||
url = f'https://{location}.tts.speech.microsoft.com/cognitiveservices/voices/list'
|
||||
|
||||
headers = {
|
||||
'Authorization': 'Bearer ' + get_access_token()
|
||||
}
|
||||
|
||||
response = requests.get(url, headers=headers)
|
||||
voices_json = json.loads(response.text)
|
||||
|
||||
first_voice = next(x for x in voices_json if x['Locale'].lower() == language.lower())
|
||||
return first_voice['ShortName']
|
||||
|
||||
voice = get_voice()
|
||||
print(f'Using voice {voice}')
|
||||
|
||||
playback_format = 'riff-48khz-16bit-mono-pcm'
|
||||
|
||||
def get_speech(text):
|
||||
url = f'https://{location}.tts.speech.microsoft.com/cognitiveservices/v1'
|
||||
|
||||
headers = {
|
||||
'Authorization': 'Bearer ' + get_access_token(),
|
||||
'Content-Type': 'application/ssml+xml',
|
||||
'X-Microsoft-OutputFormat': playback_format
|
||||
}
|
||||
|
||||
ssml = f'<speak version=\'1.0\' xml:lang=\'{language}\'>'
|
||||
ssml += f'<voice xml:lang=\'{language}\' name=\'{voice}\'>'
|
||||
ssml += text
|
||||
ssml += '</voice>'
|
||||
ssml += '</speak>'
|
||||
|
||||
response = requests.post(url, headers=headers, data=ssml.encode('utf-8'))
|
||||
return io.BytesIO(response.content)
|
||||
|
||||
def play_speech(speech):
|
||||
with wave.open(speech, 'rb') as wave_file:
|
||||
stream = audio.open(format=audio.get_format_from_width(wave_file.getsampwidth()),
|
||||
channels=wave_file.getnchannels(),
|
||||
rate=wave_file.getframerate(),
|
||||
output_device_index=speaker_card_number,
|
||||
output=True)
|
||||
|
||||
data = wave_file.readframes(4096)
|
||||
|
||||
while len(data) > 0:
|
||||
stream.write(data)
|
||||
data = wave_file.readframes(4096)
|
||||
|
||||
stream.stop_stream()
|
||||
stream.close()
|
||||
|
||||
def say(text):
|
||||
speech = get_speech(text)
|
||||
play_speech(speech)
|
||||
|
||||
def announce_timer(minutes, seconds):
|
||||
announcement = 'Times up on your '
|
||||
if minutes > 0:
|
||||
announcement += f'{minutes} minute '
|
||||
if seconds > 0:
|
||||
announcement += f'{seconds} second '
|
||||
announcement += 'timer.'
|
||||
say(announcement)
|
||||
|
||||
def create_timer(total_seconds):
|
||||
minutes, seconds = divmod(total_seconds, 60)
|
||||
threading.Timer(total_seconds, announce_timer, args=[minutes, seconds]).start()
|
||||
announcement = ''
|
||||
if minutes > 0:
|
||||
announcement += f'{minutes} minute '
|
||||
if seconds > 0:
|
||||
announcement += f'{seconds} second '
|
||||
announcement += 'timer started.'
|
||||
say(announcement)
|
||||
|
||||
def handle_method_request(request):
|
||||
if request.name == 'set-timer':
|
||||
payload = json.loads(request.payload)
|
||||
seconds = payload['seconds']
|
||||
if seconds > 0:
|
||||
create_timer(payload['seconds'])
|
||||
|
||||
method_response = MethodResponse.create_from_method_request(request, 200)
|
||||
device_client.send_method_response(method_response)
|
||||
|
||||
device_client.on_method_request_received = handle_method_request
|
||||
|
||||
while True:
|
||||
while not button.is_pressed():
|
||||
time.sleep(.1)
|
||||
|
||||
buffer = capture_audio()
|
||||
text = convert_speech_to_text(buffer)
|
||||
if len(text) > 0:
|
||||
print(text)
|
||||
message = Message(json.dumps({ 'speech': text }))
|
||||
device_client.send_message(message)
|
@ -0,0 +1,86 @@
|
||||
import json
|
||||
import threading
|
||||
import time
|
||||
from azure.cognitiveservices.speech import SpeechConfig, SpeechRecognizer, SpeechSynthesizer
|
||||
from azure.iot.device import IoTHubDeviceClient, Message, MethodResponse
|
||||
|
||||
speech_api_key = '<key>'
|
||||
location = '<location>'
|
||||
language = '<language>'
|
||||
connection_string = '<connection_string>'
|
||||
|
||||
device_client = IoTHubDeviceClient.create_from_connection_string(connection_string)
|
||||
|
||||
print('Connecting')
|
||||
device_client.connect()
|
||||
print('Connected')
|
||||
|
||||
recognizer_config = SpeechConfig(subscription=speech_api_key,
|
||||
region=location,
|
||||
speech_recognition_language=language)
|
||||
|
||||
recognizer = SpeechRecognizer(speech_config=recognizer_config)
|
||||
|
||||
def recognized(args):
|
||||
if len(args.result.text) > 0:
|
||||
message = Message(json.dumps({ 'speech': args.result.text }))
|
||||
device_client.send_message(message)
|
||||
|
||||
recognizer.recognized.connect(recognized)
|
||||
|
||||
recognizer.start_continuous_recognition()
|
||||
|
||||
speech_config = SpeechConfig(subscription=speech_api_key,
|
||||
region=location)
|
||||
speech_config.speech_synthesis_language = language
|
||||
speech_synthesizer = SpeechSynthesizer(speech_config=speech_config)
|
||||
|
||||
voices = speech_synthesizer.get_voices_async().get().voices
|
||||
first_voice = next(x for x in voices if x.locale.lower() == language.lower())
|
||||
speech_config.speech_synthesis_voice_name = first_voice.short_name
|
||||
|
||||
def say(text):
|
||||
ssml = f'<speak version=\'1.0\' xml:lang=\'{language}\'>'
|
||||
ssml += f'<voice xml:lang=\'{language}\' name=\'{first_voice.short_name}\'>'
|
||||
ssml += text
|
||||
ssml += '</voice>'
|
||||
ssml += '</speak>'
|
||||
|
||||
recognizer.stop_continuous_recognition()
|
||||
speech_synthesizer.speak_ssml(ssml)
|
||||
recognizer.start_continuous_recognition()
|
||||
|
||||
def announce_timer(minutes, seconds):
|
||||
announcement = 'Times up on your '
|
||||
if minutes > 0:
|
||||
announcement += f'{minutes} minute '
|
||||
if seconds > 0:
|
||||
announcement += f'{seconds} second '
|
||||
announcement += 'timer.'
|
||||
say(announcement)
|
||||
|
||||
def create_timer(total_seconds):
|
||||
minutes, seconds = divmod(total_seconds, 60)
|
||||
threading.Timer(total_seconds, announce_timer, args=[minutes, seconds]).start()
|
||||
announcement = ''
|
||||
if minutes > 0:
|
||||
announcement += f'{minutes} minute '
|
||||
if seconds > 0:
|
||||
announcement += f'{seconds} second '
|
||||
announcement += 'timer started.'
|
||||
say(announcement)
|
||||
|
||||
def handle_method_request(request):
|
||||
if request.name == 'set-timer':
|
||||
payload = json.loads(request.payload)
|
||||
seconds = payload['seconds']
|
||||
if seconds > 0:
|
||||
create_timer(payload['seconds'])
|
||||
|
||||
method_response = MethodResponse.create_from_method_request(request, 200)
|
||||
device_client.send_method_response(method_response)
|
||||
|
||||
device_client.on_method_request_received = handle_method_request
|
||||
|
||||
while True:
|
||||
time.sleep(1)
|
@ -0,0 +1,130 @@
|
||||
import io
|
||||
import json
|
||||
import pyaudio
|
||||
import requests
|
||||
import time
|
||||
import wave
|
||||
import threading
|
||||
|
||||
from azure.iot.device import IoTHubDeviceClient, Message, MethodResponse
|
||||
|
||||
from grove.factory import Factory
|
||||
button = Factory.getButton('GPIO-HIGH', 5)
|
||||
|
||||
audio = pyaudio.PyAudio()
|
||||
microphone_card_number = 1
|
||||
speaker_card_number = 1
|
||||
rate = 16000
|
||||
|
||||
def capture_audio():
|
||||
stream = audio.open(format = pyaudio.paInt16,
|
||||
rate = rate,
|
||||
channels = 1,
|
||||
input_device_index = microphone_card_number,
|
||||
input = True,
|
||||
frames_per_buffer = 4096)
|
||||
|
||||
frames = []
|
||||
|
||||
while button.is_pressed():
|
||||
frames.append(stream.read(4096))
|
||||
|
||||
stream.stop_stream()
|
||||
stream.close()
|
||||
|
||||
wav_buffer = io.BytesIO()
|
||||
with wave.open(wav_buffer, 'wb') as wavefile:
|
||||
wavefile.setnchannels(1)
|
||||
wavefile.setsampwidth(audio.get_sample_size(pyaudio.paInt16))
|
||||
wavefile.setframerate(rate)
|
||||
wavefile.writeframes(b''.join(frames))
|
||||
wav_buffer.seek(0)
|
||||
|
||||
return wav_buffer
|
||||
|
||||
speech_api_key = '<key>'
|
||||
location = '<location>'
|
||||
language = '<language>'
|
||||
connection_string = '<connection_string>'
|
||||
|
||||
device_client = IoTHubDeviceClient.create_from_connection_string(connection_string)
|
||||
|
||||
print('Connecting')
|
||||
device_client.connect()
|
||||
print('Connected')
|
||||
|
||||
def get_access_token():
|
||||
headers = {
|
||||
'Ocp-Apim-Subscription-Key': speech_api_key
|
||||
}
|
||||
|
||||
token_endpoint = f'https://{location}.api.cognitive.microsoft.com/sts/v1.0/issuetoken'
|
||||
response = requests.post(token_endpoint, headers=headers)
|
||||
return str(response.text)
|
||||
|
||||
def convert_speech_to_text(buffer):
|
||||
url = f'https://{location}.stt.speech.microsoft.com/speech/recognition/conversation/cognitiveservices/v1'
|
||||
|
||||
headers = {
|
||||
'Authorization': 'Bearer ' + get_access_token(),
|
||||
'Content-Type': f'audio/wav; codecs=audio/pcm; samplerate={rate}',
|
||||
'Accept': 'application/json;text/xml'
|
||||
}
|
||||
|
||||
params = {
|
||||
'language': language
|
||||
}
|
||||
|
||||
response = requests.post(url, headers=headers, params=params, data=buffer)
|
||||
response_json = json.loads(response.text)
|
||||
|
||||
if response_json['RecognitionStatus'] == 'Success':
|
||||
return response_json['DisplayText']
|
||||
else:
|
||||
return ''
|
||||
|
||||
def say(text):
|
||||
print(text)
|
||||
|
||||
def announce_timer(minutes, seconds):
|
||||
announcement = 'Times up on your '
|
||||
if minutes > 0:
|
||||
announcement += f'{minutes} minute '
|
||||
if seconds > 0:
|
||||
announcement += f'{seconds} second '
|
||||
announcement += 'timer.'
|
||||
say(announcement)
|
||||
|
||||
def create_timer(total_seconds):
|
||||
minutes, seconds = divmod(total_seconds, 60)
|
||||
threading.Timer(total_seconds, announce_timer, args=[minutes, seconds]).start()
|
||||
announcement = ''
|
||||
if minutes > 0:
|
||||
announcement += f'{minutes} minute '
|
||||
if seconds > 0:
|
||||
announcement += f'{seconds} second '
|
||||
announcement += 'timer started.'
|
||||
say(announcement)
|
||||
|
||||
def handle_method_request(request):
|
||||
if request.name == 'set-timer':
|
||||
payload = json.loads(request.payload)
|
||||
seconds = payload['seconds']
|
||||
if seconds > 0:
|
||||
create_timer(payload['seconds'])
|
||||
|
||||
method_response = MethodResponse.create_from_method_request(request, 200)
|
||||
device_client.send_method_response(method_response)
|
||||
|
||||
device_client.on_method_request_received = handle_method_request
|
||||
|
||||
while True:
|
||||
while not button.is_pressed():
|
||||
time.sleep(.1)
|
||||
|
||||
buffer = capture_audio()
|
||||
text = convert_speech_to_text(buffer)
|
||||
if len(text) > 0:
|
||||
print(text)
|
||||
message = Message(json.dumps({ 'speech': text }))
|
||||
device_client.send_message(message)
|
@ -0,0 +1,69 @@
|
||||
import json
|
||||
import threading
|
||||
import time
|
||||
from azure.cognitiveservices.speech import SpeechConfig, SpeechRecognizer
|
||||
from azure.iot.device import IoTHubDeviceClient, Message, MethodResponse
|
||||
|
||||
speech_api_key = '<key>'
|
||||
location = '<location>'
|
||||
language = '<language>'
|
||||
connection_string = '<connection_string>'
|
||||
|
||||
device_client = IoTHubDeviceClient.create_from_connection_string(connection_string)
|
||||
|
||||
print('Connecting')
|
||||
device_client.connect()
|
||||
print('Connected')
|
||||
|
||||
recognizer_config = SpeechConfig(subscription=speech_api_key,
|
||||
region=location,
|
||||
speech_recognition_language=language)
|
||||
|
||||
recognizer = SpeechRecognizer(speech_config=recognizer_config)
|
||||
|
||||
def recognized(args):
|
||||
if len(args.result.text) > 0:
|
||||
message = Message(json.dumps({ 'speech': args.result.text }))
|
||||
device_client.send_message(message)
|
||||
|
||||
recognizer.recognized.connect(recognized)
|
||||
|
||||
recognizer.start_continuous_recognition()
|
||||
|
||||
def say(text):
|
||||
print(text)
|
||||
|
||||
def announce_timer(minutes, seconds):
|
||||
announcement = 'Times up on your '
|
||||
if minutes > 0:
|
||||
announcement += f'{minutes} minute '
|
||||
if seconds > 0:
|
||||
announcement += f'{seconds} second '
|
||||
announcement += 'timer.'
|
||||
say(announcement)
|
||||
|
||||
def create_timer(total_seconds):
|
||||
minutes, seconds = divmod(total_seconds, 60)
|
||||
threading.Timer(total_seconds, announce_timer, args=[minutes, seconds]).start()
|
||||
announcement = ''
|
||||
if minutes > 0:
|
||||
announcement += f'{minutes} minute '
|
||||
if seconds > 0:
|
||||
announcement += f'{seconds} second '
|
||||
announcement += 'timer started.'
|
||||
say(announcement)
|
||||
|
||||
def handle_method_request(request):
|
||||
if request.name == 'set-timer':
|
||||
payload = json.loads(request.payload)
|
||||
seconds = payload['seconds']
|
||||
if seconds > 0:
|
||||
create_timer(payload['seconds'])
|
||||
|
||||
method_response = MethodResponse.create_from_method_request(request, 200)
|
||||
device_client.send_method_response(method_response)
|
||||
|
||||
device_client.on_method_request_received = handle_method_request
|
||||
|
||||
while True:
|
||||
time.sleep(1)
|
@ -0,0 +1,142 @@
|
||||
# Text to speech - Raspberry Pi
|
||||
|
||||
In this part of the lesson, you will write code to convert text to speech using the speech service.
|
||||
|
||||
## Convert text to speech using the speech service
|
||||
|
||||
The text can be sent to the speech service using the REST API to get speech as an audio file that can be played back on your IoT device. When requesting speech, you need to provide the voice to use as speech can be generated using a variety of different voices.
|
||||
|
||||
Each language supports a range of different voices, and you can make a REST request against the speech service to get the list of supported voices for each language.
|
||||
|
||||
### Task - get a voice
|
||||
|
||||
1. Open the `smart-timer` project in VS Code.
|
||||
|
||||
1. Add the following code above the `say` function to request the list of voices for a language:
|
||||
|
||||
```python
|
||||
def get_voice():
|
||||
url = f'https://{location}.tts.speech.microsoft.com/cognitiveservices/voices/list'
|
||||
|
||||
headers = {
|
||||
'Authorization': 'Bearer ' + get_access_token()
|
||||
}
|
||||
|
||||
response = requests.get(url, headers=headers)
|
||||
voices_json = json.loads(response.text)
|
||||
|
||||
first_voice = next(x for x in voices_json if x['Locale'].lower() == language.lower() and x['VoiceType'] == 'Neural')
|
||||
return first_voice['ShortName']
|
||||
|
||||
voice = get_voice()
|
||||
print(f'Using voice {voice}')
|
||||
```
|
||||
|
||||
This code defines a function called `get_voice` that uses the speech service to get a list of voices. It then finds the first voice that matches the language that is being used.
|
||||
|
||||
This function is then called to store the first voice, and the voice name is printed to the console. This voice can be requested once and the value used for every call to convert text to speech.
|
||||
|
||||
> 💁 You can get the full list of supported voices from the [Language and voice support documentation on Microsoft Docs](https://docs.microsoft.com/azure/cognitive-services/speech-service/language-support?WT.mc_id=academic-17441-jabenn#text-to-speech). If you want to use a specific voice, then you can remove this function and hard code the voice to the voice name from this documentation. For example:
|
||||
>
|
||||
> ```python
|
||||
> voice = 'hi-IN-SwaraNeural'
|
||||
> ```
|
||||
|
||||
### Task - convert text to speech
|
||||
|
||||
1. Below this, define a constant for the audio format to be retrieved from the speech services. When you request audio, you can do it in a range of different formats.
|
||||
|
||||
```python
|
||||
playback_format = 'riff-48khz-16bit-mono-pcm'
|
||||
```
|
||||
|
||||
The format you can use depends on your hardware. If you get `Invalid sample rate` errors when playing the audio then change this to another value. You can find the list of supported values in the [Text to speech REST API documentation on Microsoft Docs](https://docs.microsoft.com/azure/cognitive-services/speech-service/rest-text-to-speech?WT.mc_id=academic-17441-jabenn#audio-outputs). You will need to use `riff` format audio, and the values to try are `riff-16khz-16bit-mono-pcm`, `riff-24khz-16bit-mono-pcm` and `riff-48khz-16bit-mono-pcm`.
|
||||
|
||||
1. Below this, declare a function called `get_speech` that will convert the text to speech using the speech service REST API:
|
||||
|
||||
```python
|
||||
def get_speech(text):
|
||||
```
|
||||
|
||||
1. In the `get_speech` function, define the URL to call and the headers to pass:
|
||||
|
||||
```python
|
||||
url = f'https://{location}.tts.speech.microsoft.com/cognitiveservices/v1'
|
||||
|
||||
headers = {
|
||||
'Authorization': 'Bearer ' + get_access_token(),
|
||||
'Content-Type': 'application/ssml+xml',
|
||||
'X-Microsoft-OutputFormat': playback_format
|
||||
}
|
||||
```
|
||||
|
||||
This set the headers to use a generated access token, set the content to SSML and define the audio format needed.
|
||||
|
||||
1. Below this, define the SSML to send to the REST API:
|
||||
|
||||
```python
|
||||
ssml = f'<speak version=\'1.0\' xml:lang=\'{language}\'>'
|
||||
ssml += f'<voice xml:lang=\'{language}\' name=\'{voice}\'>'
|
||||
ssml += text
|
||||
ssml += '</voice>'
|
||||
ssml += '</speak>'
|
||||
```
|
||||
|
||||
This SSML sets the language and the voice to use, along with the text to convert.
|
||||
|
||||
1. Finally, add code in this function to make the REST request and return the binary audio data:
|
||||
|
||||
```python
|
||||
response = requests.post(url, headers=headers, data=ssml.encode('utf-8'))
|
||||
return io.BytesIO(response.content)
|
||||
```
|
||||
|
||||
### Task - play the audio
|
||||
|
||||
1. Below the `get_speech` function, define a new function to play the audio returned by the REST API call:
|
||||
|
||||
```python
|
||||
def play_speech(speech):
|
||||
```
|
||||
|
||||
1. The `speech` passed to this function will be the binary audio data returned from the REST API. Use the following code to open this as a wave file and pass it to PyAudio to play the audio:
|
||||
|
||||
```python
|
||||
def play_speech(speech):
|
||||
with wave.open(speech, 'rb') as wave_file:
|
||||
stream = audio.open(format=audio.get_format_from_width(wave_file.getsampwidth()),
|
||||
channels=wave_file.getnchannels(),
|
||||
rate=wave_file.getframerate(),
|
||||
output_device_index=speaker_card_number,
|
||||
output=True)
|
||||
|
||||
data = wave_file.readframes(4096)
|
||||
|
||||
while len(data) > 0:
|
||||
stream.write(data)
|
||||
data = wave_file.readframes(4096)
|
||||
|
||||
stream.stop_stream()
|
||||
stream.close()
|
||||
```
|
||||
|
||||
This code uses a PyAudio stream, the same as capturing audio. The difference here is the stream is set as an output stream, and data is read from the audio data and pushed to the stream.
|
||||
|
||||
Rather than hard coding the stream details such as the sample rate, it is read from the audio data.
|
||||
|
||||
1. Replace the contents of the `say` function to the following:
|
||||
|
||||
```python
|
||||
speech = get_speech(text)
|
||||
play_speech(speech)
|
||||
```
|
||||
|
||||
This code converts the text to speech as binary audio data, and plays the audio.
|
||||
|
||||
1. Run the app, and ensure the function app is also running. Set some timers, and you will hear a spoken response saying that your timer has been set, then another spoken response when the timer is complete.
|
||||
|
||||
If you get `Invalid sample rate` errors, change the `playback_format` as described above.
|
||||
|
||||
> 💁 You can find this code in the [code-spoken-response/pi](code-spoken-response/pi) folder.
|
||||
|
||||
😀 Your timer program was a success!
|
@ -0,0 +1,97 @@
|
||||
# Set a timer - Virtual IoT Hardware and Raspberry Pi
|
||||
|
||||
In this part of the lesson, you will set a timer on your virtual IoT device or Raspberry Pi based off a command from the IoT Hub.
|
||||
|
||||
## Set a timer
|
||||
|
||||
The command sent from the serverless function contains the time for the timer in seconds as the payload. This time can be used to set a timer.
|
||||
|
||||
Timers can be set using the Python `threading.Timer` class. This class takes a delay time and a function, and after the delay time, the function is executed.
|
||||
|
||||
### Task - set a timer
|
||||
|
||||
1. Open the `smart-timer` project in VS Code, and ensure the virtual environment is loaded in the terminal if you are using a virtual IoT device.
|
||||
|
||||
1. Add the following import statement at the top of the file to import the threading Python library:
|
||||
|
||||
```python
|
||||
import threading
|
||||
```
|
||||
|
||||
1. Above the `handle_method_request` function that handles the method request, add a function to speak a response. Fow now this will just write to the console, but later in this lesson this will speak the text.
|
||||
|
||||
```python
|
||||
def say(text):
|
||||
print(text)
|
||||
```
|
||||
|
||||
1. Below this add a function that will be called by a timer to announce that the timer is complete:
|
||||
|
||||
```python
|
||||
def announce_timer(minutes, seconds):
|
||||
announcement = 'Times up on your '
|
||||
if minutes > 0:
|
||||
announcement += f'{minutes} minute '
|
||||
if seconds > 0:
|
||||
announcement += f'{seconds} second '
|
||||
announcement += 'timer.'
|
||||
say(announcement)
|
||||
```
|
||||
|
||||
This function takes the number of minutes and seconds for the timer, and builds a sentence to say that the timer is complete. It will check the number of minutes and seconds, and only include each time unit if it has a number. For example, if the number of minutes is 0 then only seconds are included in the message. This sentence is then sent to the `say` function.
|
||||
|
||||
1. Below this, add the following `create_timer` function to create a timer:
|
||||
|
||||
```python
|
||||
def create_timer(seconds):
|
||||
minutes, seconds = divmod(seconds, 60)
|
||||
threading.Timer(seconds, announce_timer, args=[minutes, seconds]).start()
|
||||
```
|
||||
|
||||
This function takes the total number of seconds for the timer that will be sent in the command, and converts this to minutes and seconds. It then creates and starts a timer object using the total number of seconds, passing in the `announce_timer` function and a list containing the minutes and seconds. When the timer elapses, it will call the `announce_timer` function, and pass the contents of this list as the parameters - so the first item in the list gets passes as the `minutes` parameter, and the second item as the `seconds` parameter.
|
||||
|
||||
1. To the end of the `create_timer` function, add some code to build a message to be spoken to the user to announce that the timer is starting:
|
||||
|
||||
```python
|
||||
announcement = ''
|
||||
if minutes > 0:
|
||||
announcement += f'{minutes} minute '
|
||||
if seconds > 0:
|
||||
announcement += f'{seconds} second '
|
||||
announcement += 'timer started.'
|
||||
say(announcement)
|
||||
```
|
||||
|
||||
Again, this only includes the time unit that has a value. This sentence is then sent to the `say` function.
|
||||
|
||||
1. At the start of the `handle_method_request` function, add the following code to check that the `set-timer` direct method was requested:
|
||||
|
||||
```python
|
||||
if request.name == 'set-timer':
|
||||
```
|
||||
|
||||
1. Inside this `if` statement, extract the timer time in seconds from the payload and use this to create a timer:
|
||||
|
||||
```python
|
||||
payload = json.loads(request.payload)
|
||||
seconds = payload['seconds']
|
||||
if seconds > 0:
|
||||
create_timer(payload['seconds'])
|
||||
```
|
||||
|
||||
The timer is only created if the number of seconds is greater than 0
|
||||
|
||||
1. Run the app, and ensure the function app is also running. Set some timers, and the output will show the timer being set, and then will show when it elapses:
|
||||
|
||||
```output
|
||||
pi@raspberrypi:~/smart-timer $ python3 app.py
|
||||
Connecting
|
||||
Connected
|
||||
Set a one minute 4 second timer.
|
||||
1 minute 4 second timer started.
|
||||
Times up on your 1 minute 4 second timer.
|
||||
```
|
||||
|
||||
> 💁 You can find this code in the [code-timer/pi](code-timer/pi) or [code-timer/virtual-iot-device](code-timer/virtual-iot-device) folder.
|
||||
|
||||
😀 Your timer program was a success!
|
@ -0,0 +1,74 @@
|
||||
# Text to speech - Virtual IoT device
|
||||
|
||||
In this part of the lesson, you will write code to convert text to speech using the speech service.
|
||||
|
||||
## Convert text to speech
|
||||
|
||||
The speech services SDK that you used in the last lesson to convert speech to text can be used to convert text back to speech. When requesting speech, you need to provide the voice to use as speech can be generated using a variety of different voices.
|
||||
|
||||
Each language supports a range of different voices, and you can get the list of supported voices for each language from the speech services SDK.
|
||||
|
||||
### Task - convert text to speech
|
||||
|
||||
1. Open the `smart-timer` project in VS Code, and ensure the virtual environment is loaded in the terminal.
|
||||
|
||||
1. Import the `SpeechSynthesizer` from the `azure.cognitiveservices.speech` package by adding it to the existing imports:
|
||||
|
||||
```python
|
||||
from azure.cognitiveservices.speech import SpeechConfig, SpeechRecognizer, SpeechSynthesizer
|
||||
```
|
||||
|
||||
1. Above the `say` function, create a speech configuration to use with the speech synthesizer:
|
||||
|
||||
```python
|
||||
speech_config = SpeechConfig(subscription=speech_api_key,
|
||||
region=location)
|
||||
speech_config.speech_synthesis_language = language
|
||||
speech_synthesizer = SpeechSynthesizer(speech_config=speech_config)
|
||||
```
|
||||
|
||||
This uses the same API key, location and language that was used by the recognizer.
|
||||
|
||||
1. Below this, add the following code to get a voice and set it on the speech config:
|
||||
|
||||
```python
|
||||
voices = speech_synthesizer.get_voices_async().get().voices
|
||||
first_voice = next(x for x in voices if x.locale.lower() == language.lower())
|
||||
speech_config.speech_synthesis_voice_name = first_voice.short_name
|
||||
```
|
||||
|
||||
This retrieves a list of all the available voices, then finds the first voice that matches the language that is being used.
|
||||
|
||||
> 💁 You can get the full list of supported voices from the [Language and voice support documentation on Microsoft Docs](https://docs.microsoft.com/azure/cognitive-services/speech-service/language-support?WT.mc_id=academic-17441-jabenn#text-to-speech). If you want to use a specific voice, then you can remove this function and hard code the voice to the voice name from this documentation. For example:
|
||||
>
|
||||
> ```python
|
||||
> speech_config.speech_synthesis_voice_name = 'hi-IN-SwaraNeural'
|
||||
> ```
|
||||
|
||||
1. Update the contents of the `say` function to generate SSML for the response:
|
||||
|
||||
```python
|
||||
ssml = f'<speak version=\'1.0\' xml:lang=\'{language}\'>'
|
||||
ssml += f'<voice xml:lang=\'{language}\' name=\'{first_voice.short_name}\'>'
|
||||
ssml += text
|
||||
ssml += '</voice>'
|
||||
ssml += '</speak>'
|
||||
```
|
||||
|
||||
1. Below this, stop the speech recognition, speak the SSML, then start the recognition again:
|
||||
|
||||
```python
|
||||
recognizer.stop_continuous_recognition()
|
||||
speech_synthesizer.speak_ssml(ssml)
|
||||
recognizer.start_continuous_recognition()
|
||||
```
|
||||
|
||||
The recognition is stopped whilst the text is spoken to avoid the announcement of the timer starting being detected, sent to LUIS and possibly interpreted as a request to set a new timer.
|
||||
|
||||
> 💁 You can test this out by commenting out the lines to stop and restart the recognition. Set one timer, and you may find the announcement sets a new timer, which causes a new announcement, leading to a new timer, and so on for ever!
|
||||
|
||||
1. Run the app, and ensure the function app is also running. Set some timers, and you will hear a spoken response saying that your timer has been set, then another spoken response when the timer is complete.
|
||||
|
||||
> 💁 You can find this code in the [code-spoken-response/virtual-iot-device](code-spoken-response/virtual-iot-device) folder.
|
||||
|
||||
😀 Your timer program was a success!
|
@ -0,0 +1,3 @@
|
||||
# Set a timer - Wio Terminal
|
||||
|
||||
Coming soon
|
@ -0,0 +1,3 @@
|
||||
# Text to speech - Wio Terminal
|
||||
|
||||
Coming soon
|
@ -1,9 +1,17 @@
|
||||
#
|
||||
# Build a universal translator
|
||||
|
||||
## Instructions
|
||||
|
||||
A universal translator is a device that can translate between multiple languages, allowing folks who speak different languages to be able to communicate. Use what you have learned over the past few lessons to build a universal translator using 2 IoT devices.
|
||||
|
||||
> If you do not have 2 devices, follow the steps in the previous few lessons to set up a virtual IoT device as one of the IoT devices.
|
||||
|
||||
You should configure one device for one language, and one for another. Each device should accept speech, convert it to text, send it to the other device via IoT Hub and a Functions app, then translate it and play the translated speech.
|
||||
|
||||
> 💁 Tip: When sending the speech from one device to another, send the language it is in as well, making it easer to translate. You could even have each device register using IoT Hub and a Functions app first, passing the language they support to be stored in Azure Storage. You could then use a Functions app to do the translations, sending the translated text to the IoT device.
|
||||
|
||||
## Rubric
|
||||
|
||||
| Criteria | Exemplary | Adequate | Needs Improvement |
|
||||
| -------- | --------- | -------- | ----------------- |
|
||||
| | | | |
|
||||
| Create a universal translator | Was able to build a universal translator, converting speech detected by one device into speech played by another device in a different language | Was able to get some components working, such as capturing speech, or translating, but was unable to build the end to end solution | Was unable to build any parts of a working universal translator |
|
||||
|
@ -0,0 +1,212 @@
|
||||
import io
|
||||
import json
|
||||
import pyaudio
|
||||
import requests
|
||||
import time
|
||||
import wave
|
||||
import threading
|
||||
|
||||
from azure.iot.device import IoTHubDeviceClient, Message, MethodResponse
|
||||
|
||||
from grove.factory import Factory
|
||||
button = Factory.getButton('GPIO-HIGH', 5)
|
||||
|
||||
audio = pyaudio.PyAudio()
|
||||
microphone_card_number = 1
|
||||
speaker_card_number = 1
|
||||
rate = 16000
|
||||
|
||||
def capture_audio():
|
||||
stream = audio.open(format = pyaudio.paInt16,
|
||||
rate = rate,
|
||||
channels = 1,
|
||||
input_device_index = microphone_card_number,
|
||||
input = True,
|
||||
frames_per_buffer = 4096)
|
||||
|
||||
frames = []
|
||||
|
||||
while button.is_pressed():
|
||||
frames.append(stream.read(4096))
|
||||
|
||||
stream.stop_stream()
|
||||
stream.close()
|
||||
|
||||
wav_buffer = io.BytesIO()
|
||||
with wave.open(wav_buffer, 'wb') as wavefile:
|
||||
wavefile.setnchannels(1)
|
||||
wavefile.setsampwidth(audio.get_sample_size(pyaudio.paInt16))
|
||||
wavefile.setframerate(rate)
|
||||
wavefile.writeframes(b''.join(frames))
|
||||
wav_buffer.seek(0)
|
||||
|
||||
return wav_buffer
|
||||
|
||||
speech_api_key = '<key>'
|
||||
translator_api_key = '<key>'
|
||||
location = '<location>'
|
||||
language = '<language>'
|
||||
server_language = '<language>'
|
||||
connection_string = '<connection_string>'
|
||||
|
||||
device_client = IoTHubDeviceClient.create_from_connection_string(connection_string)
|
||||
|
||||
print('Connecting')
|
||||
device_client.connect()
|
||||
print('Connected')
|
||||
|
||||
def get_access_token():
|
||||
headers = {
|
||||
'Ocp-Apim-Subscription-Key': speech_api_key
|
||||
}
|
||||
|
||||
token_endpoint = f'https://{location}.api.cognitive.microsoft.com/sts/v1.0/issuetoken'
|
||||
response = requests.post(token_endpoint, headers=headers)
|
||||
return str(response.text)
|
||||
|
||||
def convert_speech_to_text(buffer):
|
||||
url = f'https://{location}.stt.speech.microsoft.com/speech/recognition/conversation/cognitiveservices/v1'
|
||||
|
||||
headers = {
|
||||
'Authorization': 'Bearer ' + get_access_token(),
|
||||
'Content-Type': f'audio/wav; codecs=audio/pcm; samplerate={rate}',
|
||||
'Accept': 'application/json;text/xml'
|
||||
}
|
||||
|
||||
params = {
|
||||
'language': language
|
||||
}
|
||||
|
||||
response = requests.post(url, headers=headers, params=params, data=buffer)
|
||||
response_json = json.loads(response.text)
|
||||
|
||||
if response_json['RecognitionStatus'] == 'Success':
|
||||
return response_json['DisplayText']
|
||||
else:
|
||||
return ''
|
||||
|
||||
def translate_text(text, from_language, to_language):
|
||||
url = f'https://api.cognitive.microsofttranslator.com/translate?api-version=3.0'
|
||||
|
||||
headers = {
|
||||
'Ocp-Apim-Subscription-Key': translator_api_key,
|
||||
'Ocp-Apim-Subscription-Region': location,
|
||||
'Content-type': 'application/json'
|
||||
}
|
||||
|
||||
params = {
|
||||
'from': from_language,
|
||||
'to': to_language
|
||||
}
|
||||
|
||||
body = [{
|
||||
'text' : text
|
||||
}]
|
||||
|
||||
response = requests.post(url, headers=headers, params=params, json=body)
|
||||
return response.json()[0]['translations'][0]['text']
|
||||
|
||||
def get_voice():
|
||||
url = f'https://{location}.tts.speech.microsoft.com/cognitiveservices/voices/list'
|
||||
|
||||
headers = {
|
||||
'Authorization': 'Bearer ' + get_access_token()
|
||||
}
|
||||
|
||||
response = requests.get(url, headers=headers)
|
||||
voices_json = json.loads(response.text)
|
||||
|
||||
first_voice = next(x for x in voices_json if x['Locale'].lower() == language.lower())
|
||||
return first_voice['ShortName']
|
||||
|
||||
voice = get_voice()
|
||||
print(f'Using voice {voice}')
|
||||
|
||||
playback_format = 'riff-48khz-16bit-mono-pcm'
|
||||
|
||||
def get_speech(text):
|
||||
url = f'https://{location}.tts.speech.microsoft.com/cognitiveservices/v1'
|
||||
|
||||
headers = {
|
||||
'Authorization': 'Bearer ' + get_access_token(),
|
||||
'Content-Type': 'application/ssml+xml',
|
||||
'X-Microsoft-OutputFormat': playback_format
|
||||
}
|
||||
|
||||
ssml = f'<speak version=\'1.0\' xml:lang=\'{language}\'>'
|
||||
ssml += f'<voice xml:lang=\'{language}\' name=\'{voice}\'>'
|
||||
ssml += text
|
||||
ssml += '</voice>'
|
||||
ssml += '</speak>'
|
||||
|
||||
response = requests.post(url, headers=headers, data=ssml.encode('utf-8'))
|
||||
return io.BytesIO(response.content)
|
||||
|
||||
def play_speech(speech):
|
||||
with wave.open(speech, 'rb') as wave_file:
|
||||
stream = audio.open(format=audio.get_format_from_width(wave_file.getsampwidth()),
|
||||
channels=wave_file.getnchannels(),
|
||||
rate=wave_file.getframerate(),
|
||||
output_device_index=speaker_card_number,
|
||||
output=True)
|
||||
|
||||
data = wave_file.readframes(4096)
|
||||
|
||||
while len(data) > 0:
|
||||
stream.write(data)
|
||||
data = wave_file.readframes(4096)
|
||||
|
||||
stream.stop_stream()
|
||||
stream.close()
|
||||
|
||||
def say(text):
|
||||
print('Original:', text)
|
||||
text = translate_text(text, server_language, language)
|
||||
print('Translated:', text)
|
||||
speech = get_speech(text)
|
||||
play_speech(speech)
|
||||
|
||||
def announce_timer(minutes, seconds):
|
||||
announcement = 'Times up on your '
|
||||
if minutes > 0:
|
||||
announcement += f'{minutes} minute '
|
||||
if seconds > 0:
|
||||
announcement += f'{seconds} second '
|
||||
announcement += 'timer.'
|
||||
say(announcement)
|
||||
|
||||
def create_timer(total_seconds):
|
||||
minutes, seconds = divmod(total_seconds, 60)
|
||||
threading.Timer(total_seconds, announce_timer, args=[minutes, seconds]).start()
|
||||
announcement = ''
|
||||
if minutes > 0:
|
||||
announcement += f'{minutes} minute '
|
||||
if seconds > 0:
|
||||
announcement += f'{seconds} second '
|
||||
announcement += 'timer started.'
|
||||
say(announcement)
|
||||
|
||||
def handle_method_request(request):
|
||||
payload = json.loads(request.payload)
|
||||
seconds = payload['seconds']
|
||||
if seconds > 0:
|
||||
create_timer(payload['seconds'])
|
||||
|
||||
method_response = MethodResponse.create_from_method_request(request, 200)
|
||||
device_client.send_method_response(method_response)
|
||||
|
||||
device_client.on_method_request_received = handle_method_request
|
||||
|
||||
while True:
|
||||
while not button.is_pressed():
|
||||
time.sleep(.1)
|
||||
|
||||
buffer = capture_audio()
|
||||
text = convert_speech_to_text(buffer)
|
||||
if len(text) > 0:
|
||||
print('Original:', text)
|
||||
text = translate_text(text, language, server_language)
|
||||
print('Translated:', text)
|
||||
|
||||
message = Message(json.dumps({ 'speech': text }))
|
||||
device_client.send_message(message)
|
@ -0,0 +1,124 @@
|
||||
import json
|
||||
import requests
|
||||
import threading
|
||||
import time
|
||||
from azure.cognitiveservices import speech
|
||||
from azure.cognitiveservices.speech import SpeechConfig, SpeechRecognizer, SpeechSynthesizer
|
||||
from azure.cognitiveservices.speech.translation import SpeechTranslationConfig, TranslationRecognizer
|
||||
from azure.iot.device import IoTHubDeviceClient, Message, MethodResponse
|
||||
|
||||
speech_api_key = '<key>'
|
||||
translator_api_key = '<key>'
|
||||
location = '<location>'
|
||||
language = '<language>'
|
||||
server_language = '<language>'
|
||||
connection_string = '<connection_string>'
|
||||
|
||||
device_client = IoTHubDeviceClient.create_from_connection_string(connection_string)
|
||||
|
||||
print('Connecting')
|
||||
device_client.connect()
|
||||
print('Connected')
|
||||
|
||||
translation_config = SpeechTranslationConfig(subscription=speech_api_key,
|
||||
region=location,
|
||||
speech_recognition_language=language,
|
||||
target_languages=(language, server_language))
|
||||
|
||||
recognizer = TranslationRecognizer(translation_config=translation_config)
|
||||
|
||||
def recognized(args):
|
||||
if args.result.reason == speech.ResultReason.TranslatedSpeech:
|
||||
language_match = next(l for l in args.result.translations if server_language.lower().startswith(l.lower()))
|
||||
text = args.result.translations[language_match]
|
||||
|
||||
if (len(text) > 0):
|
||||
print(f'Translated text: {text}')
|
||||
|
||||
message = Message(json.dumps({ 'speech': text }))
|
||||
device_client.send_message(message)
|
||||
|
||||
recognizer.recognized.connect(recognized)
|
||||
|
||||
recognizer.start_continuous_recognition()
|
||||
|
||||
speech_config = SpeechTranslationConfig(subscription=speech_api_key,
|
||||
region=location)
|
||||
speech_config.speech_synthesis_language = language
|
||||
speech_synthesizer = SpeechSynthesizer(speech_config=speech_config)
|
||||
|
||||
voices = speech_synthesizer.get_voices_async().get().voices
|
||||
first_voice = next(x for x in voices if x.locale.lower() == language.lower())
|
||||
speech_config.speech_synthesis_voice_name = first_voice.short_name
|
||||
|
||||
def translate_text(text):
|
||||
url = f'https://api.cognitive.microsofttranslator.com/translate?api-version=3.0'
|
||||
|
||||
headers = {
|
||||
'Ocp-Apim-Subscription-Key': translator_api_key,
|
||||
'Ocp-Apim-Subscription-Region': location,
|
||||
'Content-type': 'application/json'
|
||||
}
|
||||
|
||||
params = {
|
||||
'from': server_language,
|
||||
'to': language
|
||||
}
|
||||
|
||||
body = [{
|
||||
'text' : text
|
||||
}]
|
||||
|
||||
response = requests.post(url, headers=headers, params=params, json=body)
|
||||
|
||||
return response.json()[0]['translations'][0]['text']
|
||||
|
||||
def say(text):
|
||||
print('Original:', text)
|
||||
text = translate_text(text)
|
||||
print('Translated:', text)
|
||||
|
||||
ssml = f'<speak version=\'1.0\' xml:lang=\'{language}\'>'
|
||||
ssml += f'<voice xml:lang=\'{language}\' name=\'{first_voice.short_name}\'>'
|
||||
ssml += text
|
||||
ssml += '</voice>'
|
||||
ssml += '</speak>'
|
||||
|
||||
recognizer.stop_continuous_recognition()
|
||||
speech_synthesizer.speak_ssml(ssml)
|
||||
recognizer.start_continuous_recognition()
|
||||
|
||||
def announce_timer(minutes, seconds):
|
||||
announcement = 'Times up on your '
|
||||
if minutes > 0:
|
||||
announcement += f'{minutes} minute '
|
||||
if seconds > 0:
|
||||
announcement += f'{seconds} second '
|
||||
announcement += 'timer.'
|
||||
say(announcement)
|
||||
|
||||
def create_timer(total_seconds):
|
||||
minutes, seconds = divmod(total_seconds, 60)
|
||||
threading.Timer(total_seconds, announce_timer, args=[minutes, seconds]).start()
|
||||
announcement = ''
|
||||
if minutes > 0:
|
||||
announcement += f'{minutes} minute '
|
||||
if seconds > 0:
|
||||
announcement += f'{seconds} second '
|
||||
announcement += 'timer started.'
|
||||
say(announcement)
|
||||
|
||||
def handle_method_request(request):
|
||||
if request.name == 'set-timer':
|
||||
payload = json.loads(request.payload)
|
||||
seconds = payload['seconds']
|
||||
if seconds > 0:
|
||||
create_timer(payload['seconds'])
|
||||
|
||||
method_response = MethodResponse.create_from_method_request(request, 200)
|
||||
device_client.send_method_response(method_response)
|
||||
|
||||
device_client.on_method_request_received = handle_method_request
|
||||
|
||||
while True:
|
||||
time.sleep(1)
|
@ -0,0 +1,150 @@
|
||||
# Translate speech - Raspberry Pi
|
||||
|
||||
In this part of the lesson, you will write code to translate text using the translator service.
|
||||
|
||||
## Convert text to speech using the translator service
|
||||
|
||||
The speech service REST API doesn't support direct translations, instead you can use the Translator service to translate the text generated by the speech to text service, and the text of the spoken response. This service has a REST API you can use to translate the text.
|
||||
|
||||
### Task - use the translator resource to translate text
|
||||
|
||||
1. Your smart timer will have 2 languages set - the language of the server that was used to train LUIS, and the language spoken by the user. Update the `language` variable to be the language that will be spoken by the used, and add a new variable called `server_language` for the language used to train LUIS:
|
||||
|
||||
```python
|
||||
language = '<user language>'
|
||||
server_language = '<server language>'
|
||||
```
|
||||
|
||||
Replace `<user language>` with the locale name for language you will be speaking in, for example `fr-FR` for French, or `zn-HK` for Cantonese.
|
||||
|
||||
Replace `<server language>` with the locale name for language used to train LUIS.
|
||||
|
||||
You can find a list of the supported languages and their locale names in the [Language and voice support documentation on Microsoft docs](https://docs.microsoft.com/azure/cognitive-services/speech-service/language-support?WT.mc_id=academic-17441-jabenn#speech-to-text).
|
||||
|
||||
> 💁 If you don't speak multiple languages you can use a service like [Bing Translate](https://www.bing.com/translator) or [Google Translate](https://translate.google.com) to translate from your preferred language to a language of your choice. These services can then play audio of the translated text.
|
||||
>
|
||||
> For example, if you train LUIS in English, but want to use French as the user language, you can translate sentences like "set a 2 minute and 27 second timer" from English into French using Bing Translate, then use the **Listen translation** button to speak the translation into your microphone.
|
||||
>
|
||||
> 
|
||||
|
||||
1. Add the translator API key below the `speech_api_key`:
|
||||
|
||||
```python
|
||||
translator_api_key = '<key>'
|
||||
```
|
||||
|
||||
Replace `<key>` with the API key for your translator service resource.
|
||||
|
||||
1. Above the `say` function, define a `translate_text` function that will translate text from the server language to the user language:
|
||||
|
||||
```python
|
||||
def translate_text(text, from_language, to_language):
|
||||
```
|
||||
|
||||
The from and to languages are passed to this function - your app needs to convert from user language to server language when recognizing speech, and from server language to user language when provided spoken feedback.
|
||||
|
||||
1. Inside this function, define the URL and headers for the REST API call:
|
||||
|
||||
```python
|
||||
url = f'https://api.cognitive.microsofttranslator.com/translate?api-version=3.0'
|
||||
|
||||
headers = {
|
||||
'Ocp-Apim-Subscription-Key': translator_api_key,
|
||||
'Ocp-Apim-Subscription-Region': location,
|
||||
'Content-type': 'application/json'
|
||||
}
|
||||
```
|
||||
|
||||
The URL for this API is not location specific, instead the location is passed in as a header. The API key is used directly, so unlike the speech service there is no need to get an access token from the token issuer API.
|
||||
|
||||
1. Below this define the parameters and body for the call:
|
||||
|
||||
```python
|
||||
params = {
|
||||
'from': from_language,
|
||||
'to': to_language
|
||||
}
|
||||
|
||||
body = [{
|
||||
'text' : text
|
||||
}]
|
||||
```
|
||||
|
||||
The `params` defines the parameters to pass to the API call, passing the from and to languages. This call will translate text in the `from` language into the `to` language.
|
||||
|
||||
The `body` contains the text to translate. This is an array, as multiple blocks of text can be translated in the same call.
|
||||
|
||||
1. Make the call the REST API, and get the response:
|
||||
|
||||
```python
|
||||
response = requests.post(url, headers=headers, params=params, json=body)
|
||||
```
|
||||
|
||||
The response that comes back is a JSON array, with one item that contains the translations. This item has an array for translations of all the items passed in the body.
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"translations": [
|
||||
{
|
||||
"text": "Set a 2 minute 27 second timer.",
|
||||
"to": "en"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
1. Return the `test` property from the first translation from the first item in the array:
|
||||
|
||||
```python
|
||||
return response.json()[0]['translations'][0]['text']
|
||||
```
|
||||
|
||||
1. Update the `while True` loop to translate the text from the call to `convert_speech_to_text` from the user language to the server language:
|
||||
|
||||
```python
|
||||
if len(text) > 0:
|
||||
print('Original:', text)
|
||||
text = translate_text(text, language, server_language)
|
||||
print('Translated:', text)
|
||||
|
||||
message = Message(json.dumps({ 'speech': text }))
|
||||
device_client.send_message(message)
|
||||
```
|
||||
|
||||
This code also prints the original and translated versions of the text to the console.
|
||||
|
||||
1. Update the `say` function to translate the text to say from the server language to the user language:
|
||||
|
||||
```python
|
||||
def say(text):
|
||||
print('Original:', text)
|
||||
text = translate_text(text, server_language, language)
|
||||
print('Translated:', text)
|
||||
speech = get_speech(text)
|
||||
play_speech(speech)
|
||||
```
|
||||
|
||||
This code also prints the original and translated versions of the text to the console.
|
||||
|
||||
1. Run your code. Ensure your function app is running, and request a timer in the user language, either by speaking that language yourself, or using a translation app.
|
||||
|
||||
```output
|
||||
pi@raspberrypi:~/smart-timer $ python3 app.py
|
||||
Connecting
|
||||
Connected
|
||||
Using voice fr-FR-DeniseNeural
|
||||
Original: Définir une minuterie de 2 minutes et 27 secondes.
|
||||
Translated: Set a timer of 2 minutes and 27 seconds.
|
||||
Original: 2 minute 27 second timer started.
|
||||
Translated: 2 minute 27 seconde minute a commencé.
|
||||
Original: Times up on your 2 minute 27 second timer.
|
||||
Translated: Chronométrant votre minuterie de 2 minutes 27 secondes.
|
||||
```
|
||||
|
||||
> 💁 Due to the different ways of saying something in different languages, you may get translations that are slightly different to the examples you gave LUIS. If this is the case, add more examples to LUIS, retrain then re-publish the model.
|
||||
|
||||
> 💁 You can find this code in the [code/pi](code/pi) folder.
|
||||
|
||||
😀 Your multi-lingual timer program was a success!
|
@ -0,0 +1,190 @@
|
||||
# Translate speech - Virtual IoT Device
|
||||
|
||||
In this part of the lesson, you will write code to translate speech when converting to text using the speech service, then translate text using the Translator service before generating a spoken response.
|
||||
|
||||
## Use the speech service to translate speech
|
||||
|
||||
The speech service can take speech and not only convert to text in the same language, but also translate the output to other languages.
|
||||
|
||||
### Task - use the speech service to translate speech
|
||||
|
||||
1. Open the `smart-timer` project in VS Code, and ensure the virtual environment is loaded in the terminal.
|
||||
|
||||
1. Add the following import statements below the existing imports:
|
||||
|
||||
```python
|
||||
from azure.cognitiveservices import speech
|
||||
from azure.cognitiveservices.speech.translation import SpeechTranslationConfig, TranslationRecognizer
|
||||
import requests
|
||||
```
|
||||
|
||||
This imports classes used to translate speech, and a `requests` library that will be used to make a call to the Translator service later in this lesson.
|
||||
|
||||
1. Your smart timer will have 2 languages set - the language of the server that was used to train LUIS, and the language spoken by the user. Update the `language` variable to be the language that will be spoken by the used, and add a new variable called `server_language` for the language used to train LUIS:
|
||||
|
||||
```python
|
||||
language = '<user language>'
|
||||
server_language = '<server language>'
|
||||
```
|
||||
|
||||
Replace `<user language>` with the locale name for language you will be speaking in, for example `fr-FR` for French, or `zn-HK` for Cantonese.
|
||||
|
||||
Replace `<server language>` with the locale name for language used to train LUIS.
|
||||
|
||||
You can find a list of the supported languages and their locale names in the [Language and voice support documentation on Microsoft docs](https://docs.microsoft.com/azure/cognitive-services/speech-service/language-support?WT.mc_id=academic-17441-jabenn#speech-to-text).
|
||||
|
||||
> 💁 If you don't speak multiple languages you can use a service like [Bing Translate](https://www.bing.com/translator) or [Google Translate](https://translate.google.com) to translate from your preferred language to a language of your choice. These services can then play audio of the translated text. Be aware that the speech recognizer will ignore some audio output from your device, so you may need to use an additional device to play the translated text.
|
||||
>
|
||||
> For example, if you train LUIS in English, but want to use French as the user language, you can translate sentences like "set a 2 minute and 27 second timer" from English into French using Bing Translate, then use the **Listen translation** button to speak the translation into your microphone.
|
||||
>
|
||||
> 
|
||||
|
||||
1. Replace the `recognizer_config` and `recognizer` declarations with the following:
|
||||
|
||||
```python
|
||||
translation_config = SpeechTranslationConfig(subscription=speech_api_key,
|
||||
region=location,
|
||||
speech_recognition_language=language,
|
||||
target_languages=(language, server_language))
|
||||
|
||||
recognizer = TranslationRecognizer(translation_config=translation_config)
|
||||
```
|
||||
|
||||
This creates a translation config to recognize speech in the user language, and create translations in the user and server language. It then uses this config to create a translation recognizer - a speech recognizer that can translate the output of the speech recognition into multiple languages.
|
||||
|
||||
> 💁 The original language needs to be specified in the `target_languages`, otherwise you won't get any translations.
|
||||
|
||||
1. Update the `recognized` function, replacing the entire contents of the function with the following:
|
||||
|
||||
```python
|
||||
if args.result.reason == speech.ResultReason.TranslatedSpeech:
|
||||
language_match = next(l for l in args.result.translations if server_language.lower().startswith(l.lower()))
|
||||
text = args.result.translations[language_match]
|
||||
if (len(text) > 0):
|
||||
print(f'Translated text: {text}')
|
||||
|
||||
message = Message(json.dumps({ 'speech': text }))
|
||||
device_client.send_message(message)
|
||||
```
|
||||
|
||||
This code checks to see if the recognized event was fired because speech was translated (this event can fire at other times, such as when the speech is recognized but not translated). If the speech was translated, it finds the translation in the `args.result.translations` dictionary that matches the server language.
|
||||
|
||||
The `args.result.translations` dictionary is keyed off the language part of the locale setting, not the whole setting. For example, if you request a translation into `fr-FR` for French, the dictionary will contain an entry for `fr`, not `fr-FR`.
|
||||
|
||||
The translated text is then sent to the IoT Hub.
|
||||
|
||||
1. Run this code to test the translations. Ensure your function app is running, and request a timer in the user language, either by speaking that language yourself, or using a translation app.
|
||||
|
||||
```output
|
||||
(.venv) ➜ smart-timer python app.py
|
||||
Connecting
|
||||
Connected
|
||||
Translated text: Set a timer of 2 minutes and 27 seconds.
|
||||
```
|
||||
|
||||
## Translate text using the translator service
|
||||
|
||||
The speech service doesn't support translation pf text back to speech, instead you can use the Translator service to translate the text. This service has a REST API you can use to translate the text.
|
||||
|
||||
### Task - use the translator resource to translate text
|
||||
|
||||
1. Add the translator API key below the `speech_api_key`:
|
||||
|
||||
```python
|
||||
translator_api_key = '<key>'
|
||||
```
|
||||
|
||||
Replace `<key>` with the API key for your translator service resource.
|
||||
|
||||
1. Above the `say` function, define a `translate_text` function that will translate text from the server language to the user language:
|
||||
|
||||
```python
|
||||
def translate_text(text):
|
||||
```
|
||||
|
||||
1. Inside this function, define the URL and headers for the REST API call:
|
||||
|
||||
```python
|
||||
url = f'https://api.cognitive.microsofttranslator.com/translate?api-version=3.0'
|
||||
|
||||
headers = {
|
||||
'Ocp-Apim-Subscription-Key': translator_api_key,
|
||||
'Ocp-Apim-Subscription-Region': location,
|
||||
'Content-type': 'application/json'
|
||||
}
|
||||
```
|
||||
|
||||
The URL for this API is not location specific, instead the location is passed in as a header. The API key is used directly, so unlike the speech service there is no need to get an access token from the token issuer API.
|
||||
|
||||
1. Below this define the parameters and body for the call:
|
||||
|
||||
```python
|
||||
params = {
|
||||
'from': server_language,
|
||||
'to': language
|
||||
}
|
||||
|
||||
body = [{
|
||||
'text' : text
|
||||
}]
|
||||
```
|
||||
|
||||
The `params` defines the parameters to pass to the API call, passing the from and to languages. This call will translate text in the `from` language into the `to` language.
|
||||
|
||||
The `body` contains the text to translate. This is an array, as multiple blocks of text can be translated in the same call.
|
||||
|
||||
1. Make the call the REST API, and get the response:
|
||||
|
||||
```python
|
||||
response = requests.post(url, headers=headers, params=params, json=body)
|
||||
```
|
||||
|
||||
The response that comes back is a JSON array, with one item that contains the translations. This item has an array for translations of all the items passed in the body.
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"translations": [
|
||||
{
|
||||
"text": "Chronométrant votre minuterie de 2 minutes 27 secondes.",
|
||||
"to": "fr"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
1. Return the `test` property from the first translation from the first item in the array:
|
||||
|
||||
```python
|
||||
return response.json()[0]['translations'][0]['text']
|
||||
```
|
||||
|
||||
1. Update the `say` function to translate the text to say before the SSML is generated:
|
||||
|
||||
```python
|
||||
print('Original:', text)
|
||||
text = translate_text(text)
|
||||
print('Translated:', text)
|
||||
```
|
||||
|
||||
This code also prints the original and translated versions of the text to the console.
|
||||
|
||||
1. Run your code. Ensure your function app is running, and request a timer in the user language, either by speaking that language yourself, or using a translation app.
|
||||
|
||||
```output
|
||||
(.venv) ➜ smart-timer python app.py
|
||||
Connecting
|
||||
Connected
|
||||
Translated text: Set a timer of 2 minutes and 27 seconds.
|
||||
Original: 2 minute 27 second timer started.
|
||||
Translated: 2 minute 27 seconde minute a commencé.
|
||||
Original: Times up on your 2 minute 27 second timer.
|
||||
Translated: Chronométrant votre minuterie de 2 minutes 27 secondes.
|
||||
```
|
||||
|
||||
> 💁 Due to the different ways of saying something in different languages, you may get translations that are slightly different to the examples you gave LUIS. If this is the case, add more examples to LUIS, retrain then re-publish the model.
|
||||
|
||||
> 💁 You can find this code in the [code/virtual-iot-device](code/virtual-iot-device) folder.
|
||||
|
||||
😀 Your multi-lingual timer program was a success!
|
@ -0,0 +1,3 @@
|
||||
# Translate speech - Wio Terminal
|
||||
|
||||
Coming soon!
|
Binary file not shown.
After Width: | Height: | Size: 8.3 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 118 KiB |
After Width: | Height: | Size: 11 KiB |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue