[原创] EEWORLD DIY-无线电子冰箱贴

北方   2017-12-8 15:17 楼主
“无线电子冰箱贴”项目提交1. 说明 这个电子冰箱贴是一个无线连接的演示项目,实现的功能是用手机发送信息,远程显示在电子冰箱贴上。可以显示提醒的事件备忘,还可以显示当日菜谱和需要在冰箱里补充的食品。具体显示的内容是可以扩展的。 但是这个项目其实相对比较复杂,采用了wifi协议,还有z-wave协议。其中z-wave协议是通过一个UZB实现的,这一部分只是在这里展示,完整的功能并没有调试通过。 整个项目是基于树莓派实现的,在这个树莓派上同时运行着z-wave的gateway,还有本电子冰箱贴程序,也放在启动的服务项中了。 对于数据分发,使用的是pubnub协议。这个协议国内对应的产品是野狗,提供类似的一点订阅多点分发的功能。 2. 采用的硬件和服务 2.1 树莓派3 2.2 电子墨水屏 2.3 备用的使用IDT充电系统的3W无线充电套件(发送接收套件)和锂电池及充电升压模块,这部分调试通过了。不过没有包括在本项目说明中。这个也是采用电子墨水屏的原因,当系统没电时,仍然可以显示数据。 2.4 使用了pubnub服务(具体使用见后面) 2.5 z-Wave协议 2.6 基于树莓派的Raspbian 2.7 Cordova手机开发环境 3. 开发原理说明 3.1 这里用手机做一个APP,使用cordova,这样调试时直接可以用网页启动调试,不一定需要build 3.2 因为采用了pubnub协议,所以这个手机可以同时给所有定于了这条消息的显示屏同时显示。显示屏订阅了这个消息,当新消息到来就可以立刻显示出来。 4. 手机APP 4.1 首先安装好cordova,android Studio并下载需要的插件和工具。 4.2 执行“cordova create esticker” 4.3 编辑其中的index.html, 其中最重要的语句是 这个文件我下载到了本地,所以在程序中注释掉了,如果使用需要取消注释。这个是启动pubnub服务的重要文件。 源码如下
  1. <!DOCTYPE html>
  2. <html>
  3. <!--
  4. -->
  5. <head>
  6. <meta charset="utf-8" />
  7. <meta name="viewport" content="width=device-width, user-scalable=no
  8. initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
  9. <title>eSticker</title>
  10. <style>
  11. [url=home.php?mod=space&uid=568594]@import[/url] 'ui/css/evothings-app.css';
  12. </style>
  13. <script src="cordova.js"></script>
  14. <script src="libs/jquery/jquery.js"></script>
  15. <script src="libs/evothings/evothings.js"></script>
  16. <script src="libs/evothings/ui/ui.js"></script>
  17. <script src="libs/evothings/arduinoble/arduinoble.js"></script>
  18. <script src="libs/pubnub.4.18.0.js"></script>
  19. <!-- or <script src="https://cdn.pubnub.com/sdk/javascript/pubnub.4.18.0.js"></script> -->
  20. </head>
  21. <body><!-- enables low-delay CSS transitions. -->
  22. <header>
  23. <button class="back">
  24. <img src="./ui/images/arrow-left.svg" />
  25. </button>
  26. <img class="logotype" src="./ui/images/logoesticker.png" alt="eSticker" />
  27. <!--<button class="menu"><img src="ui/images/menu.svg" /></button>-->
  28. </header>
  29. <h1>eSticker</h1>
  30. <p id="info">Initializing...</p>
  31. <!--
  32. <button class="yellow wide">CONNECT</button>
  33. //New empty Keys
  34. pubnub = new PubNub({
  35. publishKey: 'pub-c-218bb0fd-bdb4-45c6-a1c4-77d7674c8caf',
  36. subscribeKey: 'sub-c-383e74cc-d0e3-11e7-b07a-4e4fd9aca72d'
  37. })
  38. -->
  39. <br />
  40. <input type="text" id="txtag" value="input text...">
  41. <button class="green wide big">Sent Text</button>
  42. <br />
  43. <button class="red wide big">Clear Text</button>
  44. <script>
  45. // Application object.
  46. var app = {}
  47. var pubnub = new PubNub({
  48. subscribeKey: 'sub-c-81c369ca-5ba6-11e7-a298-xxxxxxxxxxx', // always required
  49. publishKey: 'pub-c-6a7a7381-128c-4d9b-b3af-xxxxxxxxxxxxxx' // only required if publishing
  50. });
  51. // Function PublishMessage.
  52. function publishMessage(txMessage) {
  53. console.log("Since we're publishing on subscribe connectEvent, we're sure we'll receive the following publish.");
  54. var publishConfig = {
  55. channel : "flood_alarm_signal",
  56. message : txMessage
  57. }
  58. pubnub.publish(publishConfig, function(status, response) {
  59. console.log(status, response);
  60. })
  61. };
  62. // Connected device.
  63. app.device = null;
  64. var count=0;
  65. // Add listener and subscribing
  66. pubnub.addListener({
  67. status: function(statusEvent) {
  68. if (statusEvent.category === "PNConnectedCategory") {
  69. publishMessage("PNConnected!");
  70. }
  71. },
  72. message: function(message) {
  73. console.log("New Message!!", message);
  74. count=count+1;
  75. //app.showMessage(message.message);
  76. app.showMessage(message.message);
  77. },
  78. presence: function(presenceEvent) {
  79. // handle presence
  80. }
  81. });
  82. pubnub.subscribe({
  83. channels: ['flood_alarm_signal']
  84. });
  85. // Turn on LED.
  86. app.sentTX = function()
  87. {
  88. var txSent=new Uint8Array();
  89. txSent=document.getElementById('txtag').value;
  90. app.device && app.device.writeDataArray(new Uint8Array([txSent]), '19b10001-e8f2-537e-4f6c-d104768a1214');
  91. var txMessage = txSent;
  92. publishMessage(txMessage) ;
  93. //app.showMessage(txMessage.text);
  94. }
  95. // Turn off LED.
  96. app.clearTX = function()
  97. {
  98. document.getElementById('txtag').value = " ";
  99. app.device && app.device.writeDataArray(new Uint8Array([0]), '19b10001-e8f2-537e-4f6c-d104768a1214');
  100. }
  101. app.showMessage = function(info)
  102. {
  103. document.getElementById('info').innerHTML = info
  104. };
  105. // Called when BLE and other native functions are available.
  106. app.onDeviceReady = function()
  107. {
  108. app.showMessage('Touch the connect button to begin.');
  109. };
  110. app.connect = function()
  111. {
  112. evothings.arduinoble.close();
  113. app.showMessage('Connecting...');
  114. evothings.arduinoble.connect(
  115. 'TAG', // Advertised name of BLE device.
  116. function(device)
  117. {
  118. app.device = device;
  119. app.showMessage('Connected! Touch buttons to turn LED on/off.');
  120. },
  121. function(errorCode)
  122. {
  123. app.showMessage('Connect error: ' + errorCode + '.');
  124. });
  125. };
  126. document.addEventListener(
  127. 'deviceready',
  128. function() { evothings.scriptsLoaded(app.onDeviceReady) },
  129. false);
  130. </script>
  131. </body>
  132. </html>
4.4 生成android可执行文件apk,执行 cordova platform add android cordova build android 这样可以测试文件 cordova run android 捕获.JPG 这个是模拟器启动的情况,可以看到pubnub也启动并连接了,显示"PNConnected!",然后点击数据就可以显示在显示屏上, 捕获.JPG
esticker.apk (5.01 MB)
(下载次数: 1, 2017-12-8 14:37 上传)
生成的apk文件见附件。 实现文件发送的只有一句 publishMessage(txMessage) ; 这样的过程也太简单了了。这个完全依赖于pubnub服务的产生。 5. 使用树莓派驱动电子墨水屏 5.1 这个是waveshare微雪的1.54吋屏,随机提供了基于SPI的范例程序,不过其引脚分散在树莓派的不同位置,我就重新定义一下,尽可能接近。并定义了自己的页面,是ztag,z-wave,如下图 monocolor1.bmp 旋转后显示,文字就出现在空白的地方。 在使用前,还需要安装RPi驱动,和Image,SPIdev,python-pip等需要的packages,这样才能正确运行。 电子屏需要先初始化,然后刷新内存,最后把内存的数据显示出来,可以全屏刷新,也可以局部刷新。 5.2 源码如下
  1. ##
  2. # @filename : main.cpp
  3. # @brief : 1.54inch e-paper display demo
  4. ##
  5. import epd1in54
  6. import time
  7. import Image
  8. import ImageDraw
  9. import ImageFont
  10. from pubnub.callbacks import SubscribeCallback
  11. from pubnub.enums import PNStatusCategory
  12. from pubnub.pnconfiguration import PNConfiguration
  13. from pubnub.pubnub import PubNub
  14. pnconfig = PNConfiguration()
  15. pnconfig.subscribe_key = 'sub-c-81c369ca-5ba6-11e7-a298-xxxxxxxxxxxxxx'
  16. pnconfig.publish_key = 'pub-c-xxxxxxxxxxxxxxxxxxxxxxxxxx'
  17. pubnub = PubNub(pnconfig)
  18. def main():
  19. epd = epd1in54.EPD()
  20. epd.init(epd.lut_full_update)
  21. image = Image.new('1', (epd1in54.EPD_WIDTH, epd1in54.EPD_HEIGHT), 255) # 255: clear the frame
  22. draw = ImageDraw.Draw(image)
  23. font = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeMonoBold.ttf', 24)
  24. draw.rectangle((0, 10, 200, 34), fill = 0)
  25. epd.clear_frame_memory(0xFF)
  26. epd.set_frame_memory(image, 0, 0)
  27. epd.display_frame()
  28. epd.delay_ms(2000)
  29. # for partial update
  30. epd.init(epd.lut_partial_update)
  31. image = Image.open('/home/pi/zTag/python/monocolor.bmp')
  32. epd.set_frame_memory(image, 0, 0)
  33. epd.display_frame()
  34. epd.set_frame_memory(image, 0, 0)
  35. epd.display_frame()
  36. time_image = Image.new('1', (96, 48), 255) # 255: clear the frame
  37. draw = ImageDraw.Draw(time_image)
  38. font = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeMonoBold.ttf', 32)
  39. image_width, image_height = time_image.size
  40. def indisplay(txdata):
  41. draw.rectangle((0, 0, 96, 48), fill = 255)
  42. draw.text((0, 0), txdata, font = font, fill = 0)
  43. epd.set_frame_memory(time_image.rotate(90), 80, 80)
  44. epd.display_frame()
  45. # Pubnub start...
  46. def my_publish_callback(envelope, status):
  47. if not status.is_error():
  48. pass
  49. else:
  50. pass
  51. class MySubscribeCallback(SubscribeCallback):
  52. def presence(self, pubnub, presence):
  53. pass
  54. def status(self, pubnub, status):
  55. # print("Status category", status.category)
  56. if status.category == PNStatusCategory.PNUnexpectedDisconnectCategory:
  57. pass
  58. elif status.category == PNStatusCategory.PNConnectedCategory:
  59. pubnub.publish().channel("flood_alarm_signal").message("Hi...").async(my_publish_callback)
  60. elif status.category == PNStatusCategory.PNReconnectedCategory:
  61. pass
  62. def message(self, pubnub, message):
  63. txdata=message.message
  64. #jdata=json.dumps(txdata)
  65. print(txdata)
  66. indisplay(txdata)
  67. pubnub.add_listener(MySubscribeCallback())
  68. pubnub.subscribe().channels('flood_alarm_signal').execute()
对于pubnub的引用,需要先订阅subscribe, pubnub.subscribe().channels('flood_alarm_signal').execute() 这样在channel上的消息就可以随时接收了。这个连接是TCP连接,而且根据pubnub的说明,可以并发上千个订阅,响应速度是非常快的,而且也非常可靠。 6. 运行演示 6.1 启动树莓派的页面 捕获.JPG 可以看到z-Wave也启动了,这个版本是预制了zwave协议的版本。 6.2 执行python main.py 启动,显示连接 1.JPG 输入cool 2.JPG 显示在硬件上 3.png 其右侧是无线充电套件,直接输出的是4.85-5.25V直接的电压,可以直接在VCC和GND之间连接给树莓派和电子墨水屏供电,这个只要做一个外壳就可以的。 6.3 这项目最有意义的地方,就是使用了pubnub协议,可以实现一对多的演示,在多个手机和多个电子屏上都实现信息的广播和传输。因此应用起来就很有意义。 7. 补充说明 7.1 pubnub协议说明 这个是一个很有意思的协议,需要注册一个账号,然后申请一对key,分别实现发送和订阅,并不需要其他注册的环节,非常简便。 7.2 z-wave协议说明 这个是一个类似zigbee的低功耗协议,不过是和TI-CC1350一样是sub1GHz的协议,远距离传输更有效。但在国内几乎没有应用的领域。 此内容由EEWORLD论坛网友北方原创,如需转载或用于商业用途需征得作者同意并注明出处 本帖最后由 北方 于 2017-12-8 15:17 编辑

回复评论 (3)

可以介绍一下Cordova手机开发环境吗?是android studio的一个组件?
点赞  2017-12-23 15:39
引用: suoma 发表于 2017-12-23 15:39
可以介绍一下Cordova手机开发环境吗?是android studio的一个组件?

这个是phoneGAP的一个开源项目,用H5类似的思路开发APP。还是需要Android SDK的软硬件和思路的。不过,不如AS的开发灵活,做展示项目适合,做专业APP还是不行。需要用ionic,是cordova的丰富版本。
点赞  2017-12-25 08:55
引用: suoma 发表于 2017-12-23 15:39
可以介绍一下Cordova手机开发环境吗?是android studio的一个组件?

这个是phoneGAP的一个开源项目,用H5类似的思路开发APP。还是需要Android SDK的软硬件和思路的。不过,不如AS的开发灵活,做展示项目适合,做专业APP还是不行。
Cordova安装很简单,在python环境下联网,
pip install cordova就可以了。
使用就是如本帖所述。
点赞  2017-12-25 08:59
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复