tryer 发布的文章

物联网云平台一般都带有API接口可以实现设备及数据的自有服务器的存储以及支持对自身业务实现的更好扩展,笔者前段时间接触比较多的是有人云、TLINK,以及阿里云,ONENET,通过TASKPHP实现TLINK平台数据的抓取,定时任务,以前有人云的数据抓取、业务扩展。

  1. TASKPHP的composer安装
  2. command.php的修改
  3. taskphp的任务配置,crontab表达式的编写
  4. 具体任务操作逻辑的编写
  5. php think start 定时任务的启动

注意事项:

  1. worker_memory任务进程的最大内存配置,如果抓取任务中数据量比较大需要配置比较大的内存,不然会出错
  2. 采用supervisor来管理进程,重启容易有重复的worker进程,造成数据抓取的重复
  3. 后台任务运行 nohup php think start getdata &
  4. API接口TOKEN的获取、超时重取等
  5. 在TP5的command中可以直接采用TP的数据库操作等功能
  6. 采用了tp5的chunk进行分批处理
  7. HTTP请求采用了 Guzze库,PHP还是有不少好用的库的
  8. 执行php think start出错提示 No such file or directory

    原因:该脚本文件格式是 dos 格式 而非 unix 格式。 可以用 vim 查看或修改文件格式,命令如下 vim ./file :set
    ff // 查看 :set ff=unix // 设置文件格式为 unix
  9. fopen要开启

1. 直播间聊天室

  之前系统对接的是腾讯即时通讯IM,但免费体验版只能建10个群,原系统的直播间互动是通过腾讯IM群的方式来实现,升级到收费版价格不菲,通过分析代码发现,互动聊天的消息内容都是存放在本地数据库,利用IM只是实现了消息的不同客户端的实时广播、页面刷新,IM的高级功能比如一对一的对话、音视频通话等功能压根没有用到,所以通过用Node.js+Socket.io的方式快速建立简单的多房间的聊天室系统,调整H5页面中的相关流程与事件处理,去除了对腾讯即时通讯IM的依赖。

websocket微信开发工具中的调试
  

2.通过腾讯云实现视频直播及回放

视频参数配置
appid SecretId SecretKey

  腾讯云 API 会对每个请求进行身份验证,用户需要使用安全凭证,经过特定的步骤对请求进行签名(Signature),每个请求都需要在公共请求参数中指定该签名结果并以指定的方式和格式发送请求。

  所有的腾讯云产品的API调用 都会用这三个参数。

https://console.cloud.tencent.com/cam/capi 这里获取

https://console.cloud.tencent.com/api/explorer?Product=vod&Version=2018-07-17&Action=SearchMedia&SignVersion=
腾讯API测试

https://cloud.tencent.com/document/api
api文档中心

bizid,云推流域名,云播放域名,推流防盗链key,API鉴权KEy这些是从云直播中找到。

直播
推流地址的生成

直播客户端:小程序,PC软件

直播播放

转码后的播放地址

例如:原始播放地址为http://domain/AppName/StreamName.flv?txSecret=Md5(key+StreamName+hex(time))&txTime=hex(time) ,关联的转码模板名称为hd,则转码播放地址为http://domain/AppName/StreamName_hd.flv?txSecret=Md5(key+StreamName_hd+hex(time))&txTime=hex(time)

回放

直播录制配置,自动上传到了云点播中

可以利用API来访问到某个流产生的所有视频文件

利用API可以将同一直播的不同文件进行拼接,需要从后台设置直播课的HLS拼接,利用云点播的回调配置结合本地程序实现拼接后文件ID的更新。

请在腾讯云后台--点播---视频处理---回调配置,事件回调配置选中 拼接完成回调和转码完成回调以及回调域名。回调域名填写如下信息: 域名/addons/dg_chat/response.php

直播的时候先把推流的关掉 过一会再去点直播页面点结束,不然云点播这边还没有录制文件生成

有推流前的封面显示,有推流后显示直播画面,直播画面是从设置的直播开始时间开始播放还是有推流就开始播放

初始esp8266与nodemcu

笔者在2016年就买了套arduino的开发板套装,但只是简单的体验了下亮灯和简单的传感器就将其束之高阁了,去年有客户找我探讨物联网智能园林等系统,因为没对硬件与物联网的流程有深入的研究,所以自己是没有信心搞定,就推荐给了别人,结果还闹的十分不好,所以本人决心好好把物联网相关的知识体系研究透彻,以备后需。

笔者先是从GITHUB上采用合适的关键词搜索到了一些相关的项目代码,并且能搜索到不少企业级生产环境下的项目代码,了解到了云端代码主要就是对各种协议、如TCP、MQTT、HTTP(Websocket)等对信息进行解析、存储、逻辑处理,下发数据包。

去年买了本书《物联网python开发实战》读完很有豁然开郎,茅塞顿开的感觉 ,物联网的终端如传感器、继电器、电磁阀、GPS之类的并不是能自己就直接连入互联网的,而大多是通过一个网关来与终端、云端通讯,初学习一个领域总是有一些百度都搜索不到的疑问,通过多看书,多思考才能理解

也学习了解了下阿里云、腾讯云、百度天工的物联网解决方案,也是通过mqtt协议来管理设备,只是整合了认证等基础设施,用起来更快速方便,并能适应大规模设备的接入。

以上只是光输入知识还是得实践起来才能真正将知识内化,行动起来

起初本人是想购买一块用于arduino的上网扩展板来实验物联网,于是百度搜索到了esp8266和nodemcu,某宝花了二十几块钱买了片nodemcu、超声波、继电器回来,一看接口傻眼,这咋往arduino好插呀,然后又一顿上网看资料,才明白这东东号称arduino杀手,能独立完成连接设备上网,真是个好东东呀,并且是国人开发的,生态社区十分发达、风靡全球呀

u=1649031074,4067619692&fm=26&gp=0.jpg

固件类型

  1. at固件包 通过at指令来配置开发板 类似web开发中的模板标签、api接口等技术,不需要开发程序,只需要学会用指令就行,方便但是灵活性不高
  2. MicroPython固件 python开发
  3. nodemcu官方固件 lua语言开发,真心不太用这语言,好像有个nginx的版本可以用它来管理,游戏中也不少用这个做脚本
  4. Mongoose OS NodeJS开发,浏览器中开发
  5. arduino 采用arduino的方式开发,每次要编译上传
  6. ESPEasy WebUI的方式管理配置
  7. ESPHome https://esphome.io/ 在网页中采用纯配置的方式

根据个人的喜好技术栈来选择,将固件刷到开发板中,这里就不细说了。

微信图片_20200308115554.png
微信图片_20200308114900.png

USB转串口驱动安装

数据线一定要有数据传输功能的线,有很多线是只有充电功能的
windows10下最终我是用驱动精灵安装成功了驱动

安装Domoticz

espeasy与Domoticz结合比较方便,我是看的这篇文章才选择这种方式
智能家居折腾记 篇三:Nodemcu刷espeasy固件,制作二氧化碳检测器,并接入Domoticz

当然后来了解我这里是杀鸡用牛刀了,只是提交数据也可以用百度天工之类的云平台,domoticz和Home assistant是属于家居智能系统,比较强大,也让不小心跨入了智能家居开发的领域.

  1. domoticz中的硬件、设备配置
    硬件类型:Dummy (Does nothing, use for virtual switches only)
    然后再创建虚拟传感器 生成的Idx要配置到espeasy中
  2. espeasy中的设备、控制器配置

以上具体操作步骤可以看我推荐的文章,人家写的已经很详细

MQTT订阅的主题,可以通过别的方式编程互动
domoticz/in
domoticz/out

mqtt数据包
{"idx":4,"RSSI":10,"command":"switchlight","switchcmd":"Off"}

url控制
http://192.168.199.107/control?cmd=GPIO,14,1

关于开关类型的设置

swith button type : normal switch
我设置成了active high 所以不断的开灯又关了灯

mqtt服务器

这里选择了emqtt做为本机的mqtt broker服务器

高级应用

domoticz的事件触发器编程
espeasy的rules规则编写

第一次接触时,总觉得终端设备、电路板很难,其实慢慢了解流程和通讯规则后还是挺简单的。物联网也没有我们想的那么高大上,毕竟硬件终端能听懂的指令,提供的接口复杂度是有限的。

工具:

Domoticz 开源的智能家居/物联网控制中心
mqtt.fx MQTT调试工具
emqtt mqtt服务器
sscom 串口调试工具,这类工具很多
tcp网络调试工具

硬件与软件的设计理念有很多相通的 比如元件就是高内聚、低耦合、单一职责、接口的体现,

通过这种系统研究各类开发板的开发方式 硬件接口操作 云端系统开发 各种通讯协议的选择应用 收获满满
学习单片机确实可以更好的理解计算机系统原理 结构相比简单一些

后续学习计划

改成继电器就可以控制220v的电灯 结合其它传感器可以实现自动化智能控制
后续继续实验自建云端代码,数据库,自动操作逻辑,mqtt/tcp数据包的接收发送,
有条件再购买STM32、树莓派等强大些的开发板
购入其它的联网开发板、Lora、4g、NBiot、zigbee等,学习这些协议

做为一个中专学机械转电焊工转网页美工转开发人员的我,对电路原理电路图一脸蒙蔽,近期购买几本精典的电路原理先学习下,能看懂电路图,也为更好的理解计算机这个庞大的伟大的电路,更加热爱从事的开发工作.

学习电子电路,再拾起中专的专业 机械设计,配合多年的软件开发经验,说不定我也能走向真正创客之路呢,加油吧!终身学习!生活真美好!

笔者经常去本地的淄博图书馆借阅图书,该图书馆的藏书并不是很丰富,并不是大部分的书都能找到,一般都是有啥书就翻翻是不是合适再借阅,之前就想如果能在检索的时候显示豆瓣的评分,优先选择评价好的经典图书会比较好,图书馆官网并没有这样的功能,于是就有了下面的代码。

该代码基于thinkphp5+php7下运行,采用querylist采集组件,确实强大方便,并利用组件自带的从LARAVEL抽离的集合扩展tightenco/collect进行按评分的倒序显示.

微信图片_20200216133755.png

<?php
namespace app\index\controller;

use app\common\controller\Common;
use QL\QueryList;

class Book extends Common{

    public function index()
    {
        set_time_limit(0);
         $apikey = "0df993c66c0c636e29ecbb5344252a4a";
         $doubanurl = "https://api.douban.com/v2/book/isbn/";
        if(input('?keyword'))
        {
            $keyword = input('keyword');
            $url = "http://222.134.129.122:458/opac/search?searchWay=title&q=" . $keyword  . "&view=&searchSource=reader&booktype=&scWay=dim&marcformat=&sortWay=score&sortOrder=desc&startPubdate=&endPubdate=&rows=100&hasholding=1&curlocal=";
            //获取并按采集规则返回数据
            $rules = [
               'title' => ['.title-link','text','span'],
               'isbn'  => ['.bookcover_img','isbn'],
               'num'   => ['.bookmeta>div>span:eq(1)','text'],
                'callno' => ['.callnosSpan','text'],
               // 'holding' => ['.expressServiceTab>ul>li:eq(0)>a','text']
            ];
            //切片选择器
            $range = '.resultTable>tr';
            //echo $url;die();
            $ql = QueryList::get($url)->rules($rules)->range($range)->query();
            //匿名回调处理豆瓣信息
            $data = $ql->getData(function ($item) use ($apikey,$doubanurl) {
                $douban = QueryList::get($doubanurl . $item['isbn'] . '?apikey=' . $apikey)->getHtml();
                $doubanObj = json_decode($douban);
                if($doubanObj){
                    $item['rating'] = $doubanObj->rating->average;
                    $item['author'] = $doubanObj->author;
                    $item['pubdate'] = $doubanObj->pubdate;
                    $item['image'] = $doubanObj->image;
                    $item['publisher'] = $doubanObj->publisher;
                    $item['doubanurl'] = $doubanObj->alt;
                }
                sleep(5);
                return $item;
            });
            //dump($data->all());
            $sorted = $data->sortByDesc('rating');
            return json($sorted->all());
        }
        else
        {
            $this->error("请输入关键词");
        }

    }
}

细节调整、容错版

<?php
namespace app\index\controller;

use app\common\controller\Common;
use QL\QueryList;
use GuzzleHttp\Exception\RequestException;

class Book extends Common{

    public function index()
    {
        set_time_limit(0);
         $apikey = "0df993c66c0c636e29ecbb5344252a4a";
         $doubanurl = "https://api.douban.com/v2/book/isbn/";
        if(input('?keyword'))
        {
            $keyword = input('keyword');
            $url = "http://222.134.129.122:458/opac/search?searchWay=title&q=" . $keyword  . "&view=&searchSource=reader&booktype=&scWay=dim&marcformat=&sortWay=score&sortOrder=desc&startPubdate=&endPubdate=&rows=100&hasholding=1&curlocal=";
            //获取并按采集规则返回数据
            $rules = [
               'title' => ['.title-link','text','span'],
               'isbn'  => ['.bookcover_img','isbn'],
               'num'   => ['.bookmeta>div>span:eq(1)','text'],
                'callno' => ['.callnosSpan','text'],
               // 'holding' => ['.expressServiceTab>ul>li:eq(0)>a','text']
            ];
            //切片选择器
            $range = '.resultTable>tr';
            //echo $url;die();

            //忽略错误
            $ql1 = QueryList::getInstance();
            //注册一个myGet方法到QueryList对象
            $ql1->bind('myGet',function ($url,$args = null,$otherArgs = []){
                try{
                    $this->get($url,$args,$otherArgs);
                }catch(RequestException $e){
                    $this->setHtml('');
                    // print_r($e->getRequest());
                    echo "Http Error \r\n";
                }
                return $this;
            });

            $ql = QueryList::get($url)->rules($rules)->range($range)->query();
            //匿名回调处理豆瓣信息

            $data = $ql->getData(function ($item) use ($apikey,$doubanurl,$ql1) {

                //初始数据
                $item['image'] = "http://222.134.129.122:458/opac/media/images/book-default-small.gif";
                $item['rating'] = '0';
                $item['author'] = '';
                $item['pubdate'] = '';
                $item['image'] = '';
                $item['publisher'] = '';
                $item['doubanurl'] = '';
                //有isbn
                if($item['isbn']) {
                    try {
                        //忽略信息
                        $douban = $ql1->myGet($doubanurl . $item['isbn'] . '?apikey=' . $apikey)->getHtml();
                        $doubanObj = json_decode($douban);
                        if ($doubanObj && !isset($doubanObj->msg)) {
                            $item['rating'] = $doubanObj->rating->average;
                            $item['author'] = $doubanObj->author;
                            $item['pubdate'] = $doubanObj->pubdate;
                            $item['image'] = $doubanObj->image;
                            $item['publisher'] = $doubanObj->publisher;
                            $item['doubanurl'] = $doubanObj->alt;
                        }

                    }
                    catch (RequestException $e){
                        //echo 'Http Error';
                    }
                }
                sleep(5);
                return $item;
            });
            //dump($data->all());
            $sorted = $data->sortByDesc('rating');
            //return json($sorted->all());
            $this->assign('keyword',$keyword);
            $this->assign('books',$sorted->all());
            return $this->fetch(); // 渲染模板
        }
        else
        {
            $this->assign('books',[]);
            $this->assign('keyword','');
            return $this->fetch(); // 渲染模板
        }

    }
}