15回答

3收藏

[大赛作品提交] 基于树莓派的智能魔镜

 

Raspberry Pi Raspberry Pi 16555 人阅读 | 15 人回复 | 2018-01-09

本帖最后由 ky123 于 2018-1-31 14:05 编辑

首先,感谢E络盟官方提供的树莓派,谢谢大佬~~给大佬鞠躬,哈哈哈
---------------------------------无耻之极的分割线-----------------------------------------------
一、项目名称:pandora,基于树莓派的智能魔镜
1.原理介绍:(其实原理很简单~~)
    树莓派魔镜显示原理其实很简单,就是一块原子镜,也就是双面镜,后面放上一块屏幕,因为屏幕上面现实的字的亮度高于前面,所以,字就透过来了,同时,没有字的地方设置为黑色背景,于是人们还可以把他当作一面普通的镜子。至于显示的东西,是使用chrome浏览器的kiosk模式,(该模式说白了就是全屏模式,没有了上面的状态栏。),开机启用kiosk模式,并打开一个网页,网页的指向的地址,是本机部署的一个NodeJS服务器。
    系统架构图:
   

现在网上有很多的魔镜帖子,但是大多数服务器用的都是老外写的那个代码,神烦(不过写的很D),所以就打算自己撸一个,于是就开始了苦逼的代码之路。
2.功能介绍:
    1)显示时间,天气的信息
    2)根据编写的问候语规则,动态生成问候语,比如节日问候、天气转凉穿衣提醒、日常问候等。
    3)人脸识别功能,系统已知的人员使用镜子时,摄像头会对使用者进行人脸识别生成动态问候语,例如,你好,薇薇
    4)实时新闻抓取,支持自己编写新闻抓取插件,系统现内置OSChina新闻,新浪科技新闻,历史上的今天三种。
    5)屏幕休眠唤醒,使用时唤醒屏幕。
3.模块介绍:
    NodeJS服务器使用ExpressJS框架,前端模板使用EJS,系统分为:前端模块、新闻模块、JOB任务模块、问候语生成器、摄像头人脸识别模块。
前端模块:前端模块最为简单,主要是编写显示样式,使用的是bootstrap前端框架,EJS代码较少,主要是JS逻辑比较多,主要代码:
EJS模板代码:
  1. <!DOCTYPE html>
  2. <html>
  3.   <head>
  4.     <title><%= title %></title>
  5.     <meta name="viewport" content="width=device-width, initial-scale=1">
  6.     <link href="//cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet">
  7.     <link rel='stylesheet' href='/stylesheets/style.css' />
  8.   </head>
  9.   <body>
  10.     <div>
  11.       <div class="clock">
  12.         <div id="clock-date" class="clock-fonts-color-size-date">星期* ****年**月**日</div>
  13.         <div id="clock-hm" class="clock-fonts-color-size-hm">** : **</div>
  14.         <div id="clock-sec" class="clock-fonts-color-size-sec">**</div>
  15.       </div>

  16.       <div class="weather">
  17.         <div id="todaytemp" class="weather-today">*℃~*℃</div>
  18.         <div id="todayweather" class="weather-today">多云</div>
  19.         <div id="todaywind" class="weather-today">西北风 3-4级</div>
  20.         <div id="nowtemp" class="weather-today">实时温度:5℃(5分钟前更新)</div>
  21.         <div id="airstatus" class="weather-today">空气质量:优(30)</div>
  22.       </div>
  23.     </div>

  24.     <div class="welcome" id = "welcome">
  25.       你好,陌生人。
  26.     </div>

  27.     <div class="news" id = "news">
  28.       <div id="title" class="title"></div>
  29.       <div id="abstract" class="abstract"><div>
  30.     </div>
  31.    
  32.     <!-- javascripts -->
  33.     <script src="//cdn.bootcss.com/jquery/2.1.1/jquery.min.js"></script>
  34.     <script src="//cdn.bootcss.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
  35.     <script src="//cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
  36.     <script src="//cdn.bootcss.com/jquery-backstretch/2.0.4/jquery.backstretch.min.js"></script>
  37.     <script src="/javascripts/index.js"></script>
  38.     <script src="/javascripts/socket.io/socket.io.js"></script>
  39.   </body>
  40. </html>
复制代码
JS代码:
  1. /*
  2. * @Author: Nicot
  3. * @Date:   2016-03-29 23:12:03
  4. * @Last Modified by:   Nicot
  5. * @Last Modified time: 2018-01-09 20:50:36
  6. */

  7. //落日时间
  8. var ss = {
  9.     ssh: 18,
  10.     ssm: 0
  11. };

  12. var sr = {
  13.     srh: 6,
  14.     srm: 0
  15. };
  16. jQuery(document).ready(function() {

  17.     $.backstretch("/images/black.png");
  18.     $.updateDateTime(document);
  19.    
  20.     setInterval(function() {
  21.         //更新时间
  22.         $.updateDateTime(document);
  23.     },1000);

  24.     var socket = io();

  25.     socket.on('connect', function() {
  26.         socket.emit('hello', '你大爷');
  27.     });

  28.     socket.on('welcome', function(msg) {
  29.         var welcome = document.getElementById('welcome');
  30.         var date = new Date();
  31.         console.log(msg);
  32.         var welcomeMsg = JSON.parse(msg);
  33.         if(welcomeMsg.type == 'come' || welcomeMsg.type == 'connect') {
  34.             if(date.getHours() >= sr.srh && date.getHours() < 9) {
  35.                 welcome.innerText = '早上好,' + welcomeMsg.msg + ',开心快乐每一天哦!';
  36.             } else if(date.getHours() >= 12 && date.getHours() < ss.ssh) {
  37.                 welcome.innerText = '下午好,' + welcomeMsg.msg + '^_^';
  38.             } else if(date.getHours() >= 9 && date.getHours() < 12) {
  39.                 welcome.innerText = '上午好,' + welcomeMsg.msg + '^_^';
  40.             } else {
  41.                 welcome.innerText = '晚上好,' + welcomeMsg.msg + '^_^';
  42.             }
  43.         } else {
  44.              welcome.innerText = welcomeMsg.msg;
  45.         }
  46.         
  47.     });

  48.     socket.on('weather', function(msg) {
  49.         $.updateWeather(document, msg);
  50.     });

  51.     socket.on('news', function(msg) {
  52.         var title = document.getElementById('title');
  53.         var abstract = document.getElementById('abstract');
  54.         var news = JSON.parse(msg);
  55.         title.innerText = '[' + news.type + ']' + news.title;
  56.         abstract.innerText = news.abstract == '' ? '' : news.abstract.substring(0, 100) + '...';
  57.     });
  58. });

  59. (function($){
  60.     Date.prototype.Format = function (fmt) { //author: meizz   
  61.         var o = {  
  62.             "M+": this.getMonth() + 1, //月份   
  63.             "d+": this.getDate(), //日   
  64.             "H+": this.getHours(), //小时   
  65.             "m+": this.getMinutes(), //分   
  66.             "s+": this.getSeconds(), //秒   
  67.             "q+": Math.floor((this.getMonth() + 3) / 3), //季度   
  68.             "S": this.getMilliseconds() //毫秒   
  69.         };  
  70.         if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));  
  71.         for (var k in o)  
  72.         if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));  
  73.         return fmt;  
  74.     }

  75.     $.updateDateTime = function(doc) {
  76.         var clockhm = doc.getElementById('clock-hm');
  77.         var clocksec = doc.getElementById('clock-sec');
  78.         var clockdate = doc.getElementById('clock-date');
  79.         var weekArr = ['一', '二', '三', '四', '五', '六', '日'];
  80.         var week = weekArr[new Date().getDay()];
  81.         clockdate.innerText = new Date().Format("yyyy年MM月dd日") + " " + "星期"  + week;
  82.         clockhm.innerText = new Date().Format("HH:mm");
  83.         clocksec.innerText = new Date().Format("ss");
  84.     }

  85.     $.updateWeather = function(doc, msg) {
  86.         var weather = JSON.parse(msg);
  87.         if(weather.type == 'nowWeather') {
  88.             var nowtemp = doc.getElementById('nowtemp');
  89.             var updateTime = new Date(weather.updateTime);
  90.             nowtemp.innerText = '实时温度:' + weather.weather.tmp + '℃ 天气:' + weather.weather.cond_txt;
  91.         } else if(weather.type == 'nowAir') {
  92.             var airstatus = doc.getElementById('airstatus');
  93.             var qlty = weather.air.qlty == undefined ? '极好': weather.air.qlty;
  94.             airstatus.innerText = '空气质量:' + qlty + '(' + weather.air.aqi + ')';
  95.         } else if(weather.type == 'todayWeather') {
  96.             var todaytemp = doc.getElementById('todaytemp');
  97.             var todayweather = doc.getElementById('todayweather');
  98.             var todaywind = doc.getElementById('todaywind');
  99.             var today = weather.forecast[0];
  100.             todaytemp.innerText = today.tmp_min + '℃ ~ ' + today.tmp_max + '℃';
  101.             ss.ssh = parseInt(today.ss.split(':')[0]);
  102.             ss.ssm = parseInt(today.ss.split(':')[1]);
  103.             sr.srh = parseInt(today.sr.split(':')[0]);
  104.             sr.srm = parseInt(today.sr.split(':')[1]);
  105.             var date = new Date();
  106.             if(date.getHours() > ss.ssh && date.getMinutes() > ss.ssm) {
  107.                 todayweather.innerText = today.cond_txt_n;
  108.             } else {
  109.                 todayweather.innerText = today.cond_txt_d;
  110.             }

  111.             todaywind.innerText = today.wind_dir + ' ' + today.wind_sc + '级';
  112.         }
  113.     }
  114. })(jQuery);
复制代码
JS代码还引入了了socket.io的客户端,用于实时通信。
新闻模块:
新闻模块先包含三种新闻抓取,分别是OSChina、新浪科技、历史上的今天,新闻模块可扩展,只要添加相应的抓取代码即可。网页爬虫使用:cheerio插件。
JOB任务模块:
任务模块主要是系统的一些功能的定时任务,如:定时天气情况、空气情况、实时天气的获取与推送,问候语的定时生成与推送、新闻的定时抓取与推送、摄像头模块的检测与重启等,定时任务使用:node-schedule模块。
问候语生成器:
问候语生成器使用vm模块,动态编译用户定义的规则,生成问候语,用于支持节日问候、天气提醒等功能。规则代码例子:
  1. /*
  2. * @Author: Nicot
  3. * @Date:   2018-01-03 00:25:31
  4. * @Last Modified by:   Nicot
  5. * @Last Modified time: 2018-01-07 15:28:56
  6. */

  7. module.exports = {
  8.     random: ['weather', 'festival'],
  9.     connect: [
  10.         {
  11.             expression: 'true',
  12.             characters: ['很高兴见到你!', '你来啦~', '恭喜您成功连接系统'],
  13.             level: -1
  14.         }
  15.     ],
  16.     weather: [
  17.         {
  18.             expression: 'weather.temp < -1',
  19.             characters: ['天气有点冷~,多穿点衣服!', '天气凉,注意保暖哦', 'so cold ~~'],
  20.             level: 2
  21.         },
  22.         {
  23.             expression: 'weather.wind > 4',
  24.             characters: ['今天有大风哦,注意安全!'],
  25.             level: 1
  26.         },
  27.         {
  28.             expression: 'weather.weather == 0',
  29.             characters: ['今天有雨,别忘记带伞!', '今天可能会下雨哦~~'],
  30.             level: 3
  31.         },
  32.         {
  33.             expression: 'true',
  34.             characters: ['今天天气不错,哈哈', '风和日丽啊,祝你开心哦~'],
  35.             level: -1
  36.         }
  37.     ],
  38.     festival: [
  39.         {
  40.             expression: 'date.m == 2 && $.date.d == 18',
  41.             characters: ['祝你生日快乐哦', '生日快乐,哈哈'],
  42.             level: 3
  43.         },
  44.         {
  45.             expression: 'date.m == 2 && $.date.d == 25',
  46.             characters: ['薇薇生日快乐哦!'],
  47.             level: 3
  48.         },
  49.         {
  50.             expression: 'festival.indexOf("元旦") >= 0',
  51.             characters: ['元旦快乐~~'],
  52.             level: 3
  53.         }
  54.     ]
  55. };
复制代码
摄像头人脸识别模块:
人脸识别模块主要代码使用python编写,主要硬件包括:摄像头X1,人体识别模块X1,红外传感器X1(莫名其妙烧坏了。。。。),系统在启动时会启动一个子进程,执行python脚本,并且会定时检验脚本的存活,如果python脚本推出,则会重启脚本,人脸识别使用face++提供的接口,首先根据人体识别模块与红外传感器判断是否有人,如果有人则进行拍照,然后进行人脸识别,如果在系统内置的集合中找到该人脸,则给系统推送一个消息,并将人名推送给前台显示页面进行问候语显示。当检测到人走之后,会显示其他问候语。
4.应用源代码:https://github.com/NinthCode/pandora.git
5.硬件连接图:

6.过程照片:
原子镜

未上镜子前

屏幕

7.作品照片:

8.作品视频:
http://player.youku.com/embed/XMzMwNDY3NDI4MA==
9.源代码压缩包:
游客,如果您要查看本帖隐藏内容请回复
关注下面的标签,发现更多相似文章
分享到:
回复

使用道具 举报

回答|共 15 个

倒序浏览

沙发

ky123

发表于 2018-1-10 10:10:02 | 只看该作者

晚饭必吃,还会吃很多。
天冷,你也多穿点
板凳

carjayal

发表于 2018-2-1 19:39:59 | 只看该作者

大哥 能交个朋友吗 我自从看了你的帖子 也想做一个 材料都买到了 就差动手了+_+
地板

explorer1458

发表于 2018-3-12 20:22:07 | 只看该作者

学习了  大神能否留个QQ  我在做毕业设计  就是这个 能指导下我不
5#

zwei99999999

发表于 2018-9-21 20:34:45 | 只看该作者

原子镜?哪里有卖,能给个链接吗  谢谢
7#

yarkyyan

发表于 2018-10-17 12:45:16 | 只看该作者

你好,这个就是传说中的老变小 那个设计模型吗?谢谢
10#

lyx233

发表于 2018-12-20 08:44:15 来自手机 | 只看该作者

很不错的分享。。。。。。
您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条