微信相框-Arduino中文社区 - Powered by Discuz! Archiver

seesea 发表于 2017-10-20 23:55

微信相框

前言
之前试了微信点灯,觉得可以做个微信相册试试。

步骤
1. 材料准备:树莓派,显示屏

2. 找个外壳,又是个纸盒,把手机牌子挡住

3. 确定位置

4. 切割

5. 安装屏

6. 找个礼品包装纸来装饰下更好看

7. 包装好

8. 然后,把驱动和树莓派往盒里塞的时候,悲剧了……我,我,我去年买了个屏……屏线断了

9. 好吧,先不管屏了。服务端写好,找个服务器部署一下吧。外面有免费试用的服务器大家可以申请试用。我就拿另一个树莓派来当服务器,只是做实验嘛。自己家中的网络还需要做内网穿透,网上能找到不少,这里就不打广告了。
安装好 LAMP 环境后,把服务端程序放到 html 目录就好了(以后有空改成服务比较适合)。

10. 公众号配置指向我们的服务器地址,首先要先用官网的 valid 示例来让公众号配置通过验证,然后再改为自己的程序。具体操作网上很多教程了,就不多啰嗦啦

11. 客户端程序也上传到客户端的树莓派上

12. 这是客户端

13. 这是服务器[捂脸]

14. 小显示屏坏了,我还有大的呢,嘿嘿!
看看全家福:电视上面的 pi 是服务器,下面的 pi 是客户端,手机端的微信,最重要的最后说,大显示屏!

15. 手机上传照片到公众号

16. 大屏幕的微信相册开始显示啦!




代码
服务端主程序

<?php
// ----------------------------------------------------------------------------
// wxAlbum.php
//
// Created 2017-10-12
// By seesea <seesea2517#gmail#com>
//
// 微信相框服务端
// 时间仓促,只做演示用,待完善的功能:
// 1. 用户绑定、解绑、查询相册
// 2. 用户照片管理功能
// 3. 相册内置 id,启动时显示 id 及二维码(不过个人公众号未开放扫码功能,可以用扫码得到 id 内容后粘贴发文本的方式来绑定)
// 4. 用户、相册、照片的数据库管理
// ----------------------------------------------------------------------------

//define your token
define("TOKEN", "seesea");

define("DIR_PHOTO",               "/var/www/html/album");

define("LOG_FILE",                  "/var/www/html/log.txt");

define("MSG_INVALID_TYPE",          "无效的消息类型,仅接收文本和图片。");
define("MSG_NO_COMMAND",            "未输入命令。");
define("MSG_INVALID_SERIAL_NUM",    "无效的序列号。");
define("MSG_HELP",                  "帮助:\n上传:直接发图\n绑定:发送文本“绑定 序列号”\n解绑:发送文本“解绑 序列号/序号”,直接发送“解绑”会列出所有已绑定的相框序列号并标记序号\n全部解绑:发送文本“解绑全部”");

function logMsg($logText)
{
    file_put_contents(LOG_FILE, $logText . "\n", FILE_APPEND);
}

function downloadFile($url, $newName)
{
    $content = file_get_contents($url);
    file_put_contents($newName, $content);
}

logMsg("\n\nstart....\n");

$wechatObj = new wxAlbum();
$wechatObj->processMessage();

class wxAlbum
{
    private $xmlMsgObj;
    private $fromUsername;
    private $toUsername;
    private $msgType;

    public function __construct()
    {
      $dirs = array(DIR_PHOTO);
      foreach($dirs as $dir)
      {
            if (! file_exists($dir))
            {
                mkdir($dir);
            }
      }
    }

    public function valid()
    {
      $echoStr = $_GET["echostr"];

      //valid signature , option
      if($this->checkSignature())
      {
            echo $echoStr;
            exit;
      }
    }

    public function processMessage()
    {
      //get post data, May be due to the different environments
      $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
      logMsg($postStr);

      if (empty($postStr))
      {
            echo ""; // 回复 "success" 或空 ""
            exit;
      }

      /* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
         the best way is to check the validity of xml by yourself */
      libxml_disable_entity_loader(true);
      $this->xmlMsgObj    = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
      $this->fromUsername = $this->xmlMsgObj->FromUserName;
      $this->toUsername   = $this->xmlMsgObj->ToUserName;
      $this->msgType      = $this->xmlMsgObj->MsgType;

      switch ($this->msgType)
      {
            case "image":
                $this->processImageMessage();
                break;

            case "text":
                $this->processTextMessage();
                break;

            default:
                $this->responseUserByText(MSG_INVALID_TYPE);
      };
    }

    private function responseUserByText($msg)
    {
      $time         = time();
      $msgType      = "text";
      $textTpl      = "<xml>
                         <ToUserName><!]></ToUserName>
                         <FromUserName><!]></FromUserName>
                         <CreateTime>%s</CreateTime>
                         <MsgType><!]></MsgType>
                         <Content><!]></Content>
                         <FuncFlag>0</FuncFlag>
                         </xml>";

      $reponseXML = sprintf($textTpl, $this->fromUsername, $this->toUsername, $time, $msgType, $msg);
      echo $reponseXML;
    }

    private function processImageMessage()
    {
      $picUrl = $this->xmlMsgObj->;PicUrl;
      $filePathName = DIR_PHOTO . "/" . $this->xmlMsgObj->MsgId;
      downloadFile($picUrl, $filePathName);
      // 调试用 $this->responseUserByText("Down file: " . $filePathName);
      $this->responseUserByText("已上传服务器,文件名: " . $this->xmlMsgObj->MsgId);
    }

    private function processTextMessage($xmlMsgObj)
    {
      $keyword = trim($this->xmlMsgObj->Content);
      if (empty($keyword))
      {
            $this->responseUserByText(MSG_NO_COMMAND);
      }

      $contentStr = "收到命令:" . $keyword;
      $this->responseUserByText($contentStr);
    }

    private function showHelp()
    {
      $this->responseUserByText(MSG_HELP);
    }

    private function checkSignature()
    {
      // you must define TOKEN by yourself
      if (!defined("TOKEN"))
      {
            throw new Exception('TOKEN is not defined!');
      }

      $signature = $_GET["signature"];
      $timestamp = $_GET["timestamp"];
      $nonce = $_GET["nonce"];

      $token = TOKEN;
      $tmpArr = array($token, $timestamp, $nonce);

      // use SORT_STRING rule
      sort($tmpArr, SORT_STRING);
      $tmpStr = implode( $tmpArr );
      $tmpStr = sha1( $tmpStr );
      logMsg($tmpStr);

      if( $tmpStr == $signature )
      {
            return true;
      }else{
            return false;
      }
    }
}

?>

服务端辅助程序:查询相册服务端的照片数
<?php
// ----------------------------------------------------------------------------
// countPhotos.php
//
// Created 2017-10-21
// By seesea <seesea2517#gmail#com>
//
// 计算服务端相应相册 id 的照片
// 简单演示用,以后有空完善根据相册 ID 来获取该相册的相片数
// ----------------------------------------------------------------------------

echo (count(scandir("/var/www/html/album")) - 2)
?>

服务端辅助程序:列出相册服务端的照片名
<?php
// ----------------------------------------------------------------------------
// countPhotos.php
//
// Created 2017-10-21
// By seesea <seesea2517#gmail#com>
//
// 列出服务端相应相册 id 的照片
// 简单演示用,以后有空完善根据相册 ID 来获取该相册的相片
// ----------------------------------------------------------------------------

echo (implode(" ", array_diff(scandir("/var/www/html/album"), array(".", ".."))))
?>


客户端脚本
#!/bin/bash
# ----------------------------------------------------------------------------
# startAlbum.sh
#
# Created 2017-10-20
# By seesea <seesea2517#gmail#com>
#
# 相册客户端
# ----------------------------------------------------------------------------

PIC_DIR=pics
HTTP_SERVER="http://你的服务器地址"
COUNT_PHOTO_URL="$HTTP_SERVER/countPhotos.php"
LIST_PHOTO_URL="$HTTP_SERVER/listPhotos.php"
DOWN_PHOTO_URL="$HTTP_SERVER/album"
# QIV_COMMAND="qiv -smfD -d1 $(ls -r $PIC_DIR/*) --display :0"
mkdir $PIC_DIR 2>/dev/null

# bash -c "$QIV_COMMAND" &
# $QIV_COMMAND &
qiv -smfiD -d1 $(ls -r $PIC_DIR/* 2>/dev/null) --display :0 >/dev/null &
qiv_pid=$!

while true
do
    local_photo_count=$(ls $PIC_DIR | wc -l)
    remote_photo_count=$(curl "$COUNT_PHOTO_URL" 2>/dev/null)
    if (( local_photo_count < remote_photo_count ))
    then
      all_photo_list=$(curl "$LIST_PHOTO_URL" 2>/dev/null)
      local_photo_list=$(ls -1 $PIC_DIR)

      if [ -z "$local_photo_list" ]
      then
            local_photo_list="xxxxxxxxxxx"
      fi

      for name in $(echo -e "${all_photo_list// /\\n}" | grep -vE "$local_photo_list")
      do
            wget -q -P$PIC_DIR "$DOWN_PHOTO_URL/$name"
      done

      kill $qiv_pid
      qiv -smfiD -d1 $(ls -r $PIC_DIR/* 2>/dev/null) --display :0 >/dev/null &
      qiv_pid=$!
    fi

    sleep 1; # 测试用的间隔短一些,方便更快看到结果
done
视频
http://v.youku.com/v_show/id_XMzEwMDEyNjUyNA

seesea 发表于 2017-11-18 18:12


衣服和抽奖奖品到啦!秀出来




牙牙乐 发表于 2017-11-24 11:38

你好,你的客户端的树莓派是怎么和显示屏连接的?

seesea 发表于 2017-11-24 12:44

牙牙乐 发表于 2017-11-24 11:38
你好,你的客户端的树莓派是怎么和显示屏连接的?

电视有hdmi接口^_^

牙牙乐 发表于 2017-11-28 20:55

本帖最后由 牙牙乐 于 2017-12-6 10:11 编辑

seesea 发表于 2017-11-24 12:44
电视有hdmi接口^_^
你好,能加你好友,请教你一下吗?谢谢了

牙牙乐 发表于 2017-12-6 10:18

你好,我想请教你一下。按照你的实验过程,我做了一遍,基本能够实现功能,只不过大多数时候从微信公众号中上传到的图片会保存在服务器上,但是客户端并不下载,只有将pics文件夹下的照片删掉几张之后才会显示刚上传的图片。而且终端下一直提示
line 37:grep:command not found
line 42;kill:No such process.
能帮我分析分析是哪里有问题吗?代码没变,对这个很感兴趣,但是shell语言不太熟,看不太懂。

牙牙乐 发表于 2017-12-6 10:22

还有就是,客户端的这个脚本是只执行一次就行了是吗?我想要停止播放的时候就按ESC退出,然后会又运行一遍这个shell脚本,不知道是不是这个原因,会看到pics这个文件夹下的同一张图片会有好几张。

seesea 发表于 2017-12-11 21:28

牙牙乐 发表于 2017-12-6 10:18
你好,我想请教你一下。按照你的实验过程,我做了一遍,基本能够实现功能,只不过大多数时候从微信公众号中 ...

抱歉有点忙,没怎么上线。

你这提示 grep command not found 有点奇怪,检查一下文件的命令拼写是不是正确,看有没有带上特殊的符号什么的,如果文件没有问题,那你在控制终端下执行grep 命令看看是不是能用,这个提示是说你系统没有 grep 命令。

kill 这个提示是不是你另外有手工杀进程导致找不到脚本之前启动的 qiv 子进程了。

seesea 发表于 2017-12-11 21:34

牙牙乐 发表于 2017-12-6 10:22
还有就是,客户端的这个脚本是只执行一次就行了是吗?我想要停止播放的时候就按ESC退出,然后会又运行一遍 ...

同一个图片有好几张?不都是同名的嘛,应该要覆盖才是。另外,上一个问题中的grep 命令就是用来过滤已经下载的图片不再下载的,由于有之前的错误所以可能重复下载了。

脚本的执行参考帖子的 11 点的截图,执行一次,加 & 号表示放后台执行,这样就可以了不用管了,退出终端都会继续执行的。

要做停止播放这个功能要另外加代码处理,简单用就这样啦,比较麻烦也没时间做,所以就匆匆完工了。

牙牙乐 发表于 2017-12-14 09:39

您好,真的很感谢您的耐心解答。这几天我看了京东上买的微信相框,有播放视频的功能,我想请教您一下,有没有这样的软件可以支持这样的功能,既能播放图片又能播放视频,还有相应的播放指令,在shell脚本下执行?
页: [1] 2
查看完整版本: 微信相框