uni-app入门
资源
使用阿里云小程序开发工具
- 新建->mPaaS->Uni APP, 编译会失败, 查看日志, 会提示没有
cross-env
, 需要选择左侧的npm依赖管理
图标, 在开发依赖
中增加cross-env
cross-env
, 需要选择左侧的npm依赖管理
图标, 在开发依赖
中增加cross-env
这儿有一个对比: https://blog.csdn.net/qq_32279193/article/details/109130401
在阿里提供的小程序开发平台中, 基于mPaaS的小程序开发中, 有uni-app和remax两个选项.
其中uni-app是dcloud制作的基于vue的跨平台小程序发布, remax是基于react构建跨平台小程序的工具
基于 阿里的mPaaS https://help.aliyun.com/document_detail/49549.html
需要下载IDE
https://help.aliyun.com/document_detail/67444.html
https://help.aliyun.com/document_detail/172408.html
uni-app要做的是对小程序的一次开发到处运行. Dcloud做的, 理念我很喜欢, 就是官网有点儿山寨.
uni-app的项目结构和node项目/vue-cli创建的项目非常像, 都有package.json
, node_modules/
, 以及src/
下的main.js, app.vue
, 编译后都会生成到dist/
目录.
然而并非支持vue的库或者其他npm库在这儿都可以用. 比如vuetify
就用不了. 怎么判断能不能用,哪些能用, 在uni-app的论坛里讲到:
https://ask.dcloud.net.cn/article/35489
总之, vuetify必须得换成其他实现方式了.
uni-app又基于了另一个mpvue工具. mpvue是将vue移植到小程序平台上运行的库. megalo是另一个类似功能的库. 似乎uni-app都有支持.
邀黑桃三回答个问题😁:
怎么做到链接跳转时站外新页面, 站内当前页面?
原文https://pyserial.readthedocs.io/en/latest/tools.html
安装pyserial
python -m pip install pyserial
使用Miniterm工具
python -m serial.tools.miniterm COM5 115200
在cmd
命令行窗口支持ESC颜色
python -m serial.tools.miniterm COM5 115200 -f direct
远程不能直接使用vscode idf插件的命令行, 需要打开idf插件的配置,将其中的path等信息改成bat
运行一下.
示例如下:
set path=D:\r\esp\.espressif\tools\xtensa-esp32-elf\esp-2021r2-8.4.0\xtensa-esp32-elf\bin;D:\r\esp\.espressif\tools\xtensa-esp32s2-elf\esp-2021r2-8.4.0\xtensa-esp32s2-elf\bin;D:\r\esp\.espressif\tools\xtensa-esp32s3-elf\esp-2021r2-8.4.0\xtensa-esp32s3-elf\bin;D:\r\esp\.espressif\tools\riscv32-esp-elf\esp-2021r2-8.4.0\riscv32-esp-elf\bin;D:\r\esp\.espressif\tools\esp32ulp-elf\2.28.51-esp-20191205\esp32ulp-elf-binutils\bin;D:\r\esp\.espressif\tools\esp32s2ulp-elf\2.28.51-esp-20191205\esp32s2ulp-elf-binutils\bin ;D:\r\esp\.espressif\tools\cmake\3.20.3\bin;D:\r\esp\.espressif\tools\openocd-esp32\v0.10.0-esp32-20211111\openocd-esp32\bin;D:\r\esp\.espressif\tools\ninja\1.10.2;D:\r\esp\.espressif\tools\idf-exe\1.0.3;D:\r\esp\.espressif\tools\ccache\4.3\ccache-4.3-windows-64;D:\r\esp\.espressif\tools\dfu-util\0.9\dfu-util-0.9-win64;D:\r\esp\.espressif\tools\idf-git\2.30.1\cmd\;D:\r\esp\.espressif\python_env\idf4.4_py3.8_env\Scripts\;%PATH%
set IDF_PATH=d:\r\esp\esp-idf\
set IDF_TOOLS_PATH=D:\r\esp\.espressif
Set OPENOCD_SCRIPTS=D:\\r\\esp\\.espressif\\tools\\openocd-esp32\\v0.10.0-esp32-20211111/openocd-esp32/share/openocd/scripts
set IDF_CCACHE_ENABLE=1
还有一种方式是在esp-idf
下有一些export.bat/.sh
文件, 是用于配置idf环境的,不过可能需要修改.
通过 SSHFS windows manager
可以挂载远程硬盘. 参考文章
项目地址: https://github.com/tencentyun/qcloud-iot-esp-wifi/tree/master/qcloud-iot-esp8266-demo
文档地址: https://cloud.tencent.com/document/product/1081/48370
8266项目的SDK又是基于腾讯的C SDK抽取的, C SDK地址: https://github.com/tencentyun/qcloud-iot-explorer-sdk-embedded-c
8266项目目录下components/qcloud_iot/qcloud_iot_c_sdk/includes
中的几个文件是要修改的参数和调用的api放置的地方.
还有三元组信息在 components/qcloud_iot/qcloud_iot_c_sdk/platform
下的HAL_Device_freertos.c
文件中. 居然不是在头文件里定义, 感觉挺糟糕的.
qcloud_iot_export.h
这个qcloud_iot_export.h
文件实际上include了所有在exports
目录里面的.h文件. 所有的接口API在其中描述.
qcloud_iot_export_variables.h
MQTT的心跳时间240s建议改为200s. 默认240s与服务器端太一致了, 设备时钟慢一点就会被服务器踢出.
/* default MQTT keep alive interval (unit: ms) */
#define QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL (200 * 1000) // 原设置: 240*1000
HAL_Device_freertos.c
#ifdef DEBUG_DEV_INFO_USED
/* product Id */
static char sg_product_id[MAX_SIZE_OF_PRODUCT_ID + 1] = "PRODUCT_ID"; // 修改
/* device name */
static char sg_device_name[MAX_SIZE_OF_DEVICE_NAME + 1] = "YOUR_DEV_NAME"; // 根据mac生成的话, 需要在代码中动态修改 . 似乎应该在HAL_SetDevInfo()调用前或者干脆就在这个函数里修改
/* device secret of PSK device */
static char sg_device_secret[MAX_SIZE_OF_DEVICE_SECRET + 1] = "YOUR_IOT_PSK";
/* region */
static char sg_region[MAX_SIZE_OF_PRODUCT_REGION + 1] = "ap-guangzhou";
#ifdef GATEWAY_ENABLED
/* sub-device product id */
static char sg_sub_device_product_id[MAX_SIZE_OF_PRODUCT_ID + 1] = "PRODUCT_ID";
/* sub-device device name */
static char sg_sub_device_name[MAX_SIZE_OF_DEVICE_NAME + 1] = "YOUR_SUB_DEV_NAME";
#endif
#ifdef DEV_DYN_REG_ENABLED
/* product secret for device dynamic Registration */
static char sg_product_secret[MAX_SIZE_OF_PRODUCT_SECRET + 1] = "YOUR_PRODUCT_SECRET"; // 动态验证需要改这儿
#endif
component.mk
如果在main
目录下自定义了新的文件夹用于放源码, 需要将这个文件夹加入编译路径 ,在component.mk
中, 如增加一行:
COMPONENT_SRCDIRS += ./lamploop
在samples
目录下有4个demo程序, 实际上是根据sdkconfig
里面的配置选择不同的demo进行编译. 以data_template_light
的主流程示例如下:
main.c中的app_main()创建qcloud_demo_task任务
-->演示获取WIFI信息
-->联网
-->设置时间服务器
-->调用主逻辑qcloud_iot_explorer_demo
-->qcloud_iot_explorer_demo在samples/data_template_light/light_data_template_sample.c中定义
-->初始化连接信息_setup_connect_init_params
-->构建物模型也就是所谓的数据模板IOT_Template_Construct
-->初始化数据模板_init_data_template
-->注册模板属性_register_data_template_property
-->注册模板动作_register_data_template_action
-->获取系统信息_get_sys_info, 并上报IOT_Template_Report_SysInfo_Sync
-->获取数据状态IOT_Template_GetStatus_sync
-->处理下行数据逻辑deal_down_stream_user_logic
-->使能ota任务enable_ota_task
-->初始化报告时钟
-->倒计时10秒
-->进入task的死循环
-->断开连接(!IOT_Template_IsConnected)超过20秒直接跳出死循环
-->判断固件在下载is_fw_downloading, 睡0.5秒后,进入下次循环
-->收到控制消息sg_control_msg_arrived
-->进入控制信令处理deal_down_stream_user_logic
-->回复服务器IOT_Template_ControlReply
-->构造变化属性的报告deal_up_stream_user_logic(pReportDataList, &ReportCount)
-->如果属性有变化, 则构造报告数组IOT_Template_JSON_ConstructReportArray
-->上传报告数组IOT_Template_Report
-->如果开启了事件处理, 则进行事件处理.
-->睡到1秒
-->如果各种原因跳出了循环(看到的原因只有断开连接)
-->关闭ota任务
-->销毁模板
下面基于乐鑫的v3.1example/project_template
项目基础上, 增加qcloud_iot功能
为解说方便, 将qcloud-iot-esp8266-demo
项目称之为qcloud
项目, 将将project_template
项目称之为template
项目
components\qcloud_iot\qcloud_iot_c_sdk
目录复制到template项目的components\qcloud_iot_c_sdk
,去掉一级目录qcloud_iot
.components\component.mk
复制过来sdkconfig
复制过来, 或者进入make menuconfig
手动修改. 主要要改component config-->SSL-->mbedTLS
下的内容:
在`TLS Key Exchange Methods`下修改:
要深入了解文档,还是要看C-SDK项目的示例而不是8266-C-SDK的项目示例
qcloud-iot-explorer-sdk-embedded-c
视频教程
https://git.code.tencent.com/hubertxxu/qcloud_iot_explorer_esp8266
参考https://code.visualstudio.com/docs/remote/ssh-tutorial
远程开发的机器称为服务器, 如果是win10的话, 要安装并运行sshd服务, 并且服务使用powershell
作为命令行, 参见前一篇文章.
如果开发服务器在内网,可以使用中转穿透服务frp.
如果都装好了, 使用ssh也可以登录了, 如果是通过frp登录的话, 命令可能是ssh username@frp_server_ip -p 7777 -oPort=7000
, 其中7777是frpc客户端(也就是开发服务器)要求frps服务端开启的端口, 7000是frps固有服务端口.
在vscode上点击左下角, 选择connect to host...
输入ssh命令, 不需要输入-oPort=7000
部分,按说明还需要加一个-A
(干吗用的还不知道), 如: ssh username@frp_server_ip -p 7777 -A
然后就可以连接成功了.
如果远程开发服务器上有docker容器, 可以在vscode的cmd窗口进入docker容器, 命令如下:
docker exec -it 容器名 /bin/bash
如果容器里面没有bash
还可以把bash换成sh
有个很有意思的现象: 如果vscode连接的开发服务器必须同时开着sshd
和frpc
, 但是如果vscode已经连上了, sshd
就可以关掉了, 只开着frpc
就可以.这时候ssh
命令行已经无法连接上了. 似乎vscode借用了22端口,但连接上以后没有走sshd协议
参考https://winaero.com/enable-openssh-server-windows-10/#:~:text=Enable%20the%20OpenSSH%20Server%20in%20Windows%2010%201,on%20the%20Install%20button.%205%20Restart%20Windows%2010.
https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse
SSH服务器
和SSH客户端
都安装.C:\windows\system32\OpenSSH
目录下就会安装ssh的相关文件, 包括sshd.exe
, 可以直接运行sshd就开启服务,也可以按文章的介绍在服务
中开启.services.msc
, 查看OpenSSH SSH server
项, 双击, 选择登录
页面,查看或修改可以登录的用户. 设置服务为自动
并开启运行.cmd
,运行ssh-keygen -A
生成服务端key, 默认生成的位置在C:\ProgramData\ssh
. 这儿还存放sshd_config
文件, 如果没有就创建一个.ssh-keygen
,生成本地ssh keyid_rsa
和id_rsa.pub
,位置在C:\Users\username/.ssh/
,这儿还存放authorized_keys
. authorized_keys
就是其他客户端的pub key的集合ssh-keygen
,生成本地ssh keyid_rsa
和id_rsa.pub
, 将id_rsa.pub
复制一份改名为authorized_keys
到服务端的C:\Users\username/.ssh/
目录regedit
, New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force
当然你也可以改成其他命令行如cmd
或者bash
,但是如果要使用vscode远程的话必须设置为如上的powershell
总结: 涉及的目录和注册表有以下几项:
软件安装目录: C:\windows\system32\OpenSSH
服务key存放目录: C:\ProgramData\ssh
用户Key存放目录: C:\Users\username/.ssh/
服务名: OpenSSH SSH Server, 或 sshd
注册表项: HKLM:\SOFTWARE\OpenSSH, DefaultShell
官网示例是针对端口全开的公网ip, 而阿里云是有安全策略, 需要开放端口.
frp用起来算是及其简单惬意了.
systemd
系统服务. 先进入frp解压目录, 然后是如下步骤:cp systemd/*.* /usr/lib/systemd/system/
cp frps /usr/bin/
chmod +x /usr/bin/frps
mkdir /etc/frp
cp frps.ini /etc/frp/
systemctl start frps
systemctl status frps
最后一条命令可以看到frps是否启动成功.
可以看一下cat /etc/frp/frps.ini
的内容, 默认是:
[common]
bind_port = 7000
这时候可以看一下frps的端口占用:
#netstat -tunlp|grep frps
tcp6 0 0 :::7000 :::* LISTEN 4928/frps
aliyun.com
, 在ECS服务器->实例->安全组
中的入方向
添加一条TCP记录, 端口号写一个区间:7000/7100
.后面frp配置的所有端口号都要在这个范围内才能访问. 授权对象为0.0.0.0/0
frpc.ini
,假设服务器地址是x.x.x.x
,如下:
[common]
server_addr = x.x.x.x
server_port = 7000
[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 7001
运行`frpc`
5.这时候可以回到阿里云服务器看一下frps的端口占用,发现服务器打开了7001端口:
tcp6 0 0 :::7000 ::: LISTEN 4928/frps
tcp6 0 0 :::7001 ::: LISTEN 4928/frps
6. SSH客户端连接SSH服务器
ssh username@x.x.x.x -p 7001 -oPort=7000
https://zhuanlan.zhihu.com/p/303175108
本想用ngork, 然而注册总是不成功. 另一个natapp的页面看起来似乎运营实力一般,再加上免费版本有些限制, 所以就看了看其他的方式.
因为有个阿里云的服务器, 最后选择frp
注意: 固件编译只能通过 docker进行.
原因是:
xtensa-lx106-elf-linux64-1.22.0-92-g8facf4c-5.2.0.tar.gz
), 所以干脆用了腾讯提供的docker img了.docker img获取方式: docker pull hubertxxu/esp8266_build:0.1
, 由腾讯的xph
提供.
docker项目文件夹在/r/
下.
docker linux 版本:
uname -a
Linux bff9dfda8fd0 5.10.16.3-microsoft-standard-WSL2 #1 SMP Fri Apr 2 22:23:49 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
支持yum install
命令
docker容器挂载windows目录的启动方式:
docker run --name esp -v path/to/host/folder:/path/to/container/folder -dt hubertxxu/esp8266_build:0.1
挂载以后进行编译.
container修改esp工具链可访问性
chmod -R 777 /home/esp8266
cd /etc
mv yum.repos.d yum.repos.d.backup
mkdir yum.repos.d
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-8.repo
另外, dnf
是比yum更先进的包管理工具,可以换用dnf
使用了下面一长串的命令启动了ssh, 但是docker内的ip不是真实ip,host ping container是不通的. 我在host上建立了ftp server,通过container登录来看container的ip,发现竟然就是host的ip.
使用如下步骤开启了sshd
yum install net-tools
yum install openssh-server
yum install passwd
mkdir -p /var/run/sshd
ssh-keygen -A
然后编辑sshd配置
vi /etc/ssh/sshd_config
打开以下配置
Port 22
ListenAddress 0.0.0.0
PasswordAuthentication Yes
设置root密码
passwd
启动服务
/usr/sbin/sshd -D &
查看进程和端口占用
ps -A
netstat -nptl
本地连接测试
ssh localhost
最近做完了通过8266 Qcloud AT做腾讯连连的台灯的项目, 使用enum做连接状态记录, 在做网络连接的过程中发现了一些问题, 这儿讨论一下.
typedef enum _ESP_STATUS{
ESP_STATUS_INIT,
ESP_STATUS_READY,
ESP_STATUS_GOT_MAC,
ESP_STATUS_CONFIGED_NTP_SERVER,
ESP_STATUS_GOT_TIME,
ESP_STATUS_CONNECTED_MQTT,
ESP_STATUS_SUBED_MQTT,
ESP_STATUS_WIFI_DISCONNECTTED,
}ESP_STATUS;
上面这种enum用下划线, type去掉下划线, 并在枚举项内体现type名称的命名习惯从华为开始就确定了. 这个不需要讨论.
从上到下依次为按时间顺序会依次进入的状态, 这个也没有问题.
GOT_MAC
先动作再对象也是对的.
想讨论的READY/GOT/CONFIGED
这种过去时态. 我认为不如进行时态. 过去时态会造成当前状态与上一个状态在意义上的耦合. 因为READY以后就要获取MAC, 所以READY
不如改名为GETTING_MAC
, GOT_MAC
不如改名为CONFIGING_NTP_SERVER
. 也就是凡是要主动做操作的, 都用进行时态.
另外还有一种是处在状态中不主动动作, 而是被动等待状态改变(相当于什么也不做). 名称应改为WAITFOR_DO_XXX
, 如WAITFOR_RECONNECT_WIFI
.
修改如下:
typedef enum _ESP_STATUS{
ESP_STATUS_WAITFOR_READY,
ESP_STATUS_GETTING_MAC,
ESP_STATUS_CONFIGING_NTP_SERVER,
ESP_STATUS_GETTING_TIME,
ESP_STATUS_CONNECTING_MQTT,
ESP_STATUS_SUBING_MQTT,
ESP_STATUS_REPORTING_MQTT_PROPERTY,
ESP_STATUS_WAITFOR_CONNECT_WIFI
}ESP_STATUS;
其中, ESP_STATUS_SUBING_MQTT
又可以分为对SERVICE和PROPERTY分别SUB, 两者虽然没有先后之分, 但是仍应该人为规定先后顺序并放入枚举项中. 改为:
typedef enum _ESP_STATUS{
ESP_STATUS_INIT, // 这时候等待READY
ESP_STATUS_GETTING_MAC,
ESP_STATUS_CONFIGING_NTP_SERVER,
ESP_STATUS_GETTING_TIME,
ESP_STATUS_CONNECTING_MQTT,
ESP_STATUS_SUBING_MQTT_SERVICE,
ESP_STATUS_SUBING_MQTT_PROPERTY,
ESP_STATUS_REPORTING_MQTT_PROPERTY,
}ESP_STATUS;
.h文件
是用来放置public公有性质的内容, #define 常量
, typedef enum
, typedef struct
, extern 全局变量
, 公用函数声明返回值 函数值(参数列表);
. 不可以做c文件的私有全局变量声明, 也不可以做函数定义, 也不可以做c文件私有函数声明.
.c文件
用来放置公有和私有的全局变量定义, 私有函数声明, 共有和私有的函数定义.
.h
文件内部由于有了#ifndef 头文件名 #define 头文件名 #endif
的结构, 所以可以#include
其他.h
文件.
.c
文件任何时候都不应被其他文件#include
将1对同名.h
和.c
文件作为一个模块的话, 项目中为模块划分层次, 底层模块为上层提供服务, 设置基本共识. 需要注意的是上层模块可以#include下层模块, 但下层模块不能#include上层模块, 也就是说, 下层不应依赖上层, 上层的任何变化不应使下层模块无法使用, 无论上层如何变化下层都应提供一致的服务.
为进一步让上层解耦, 摆脱对特定实现方式的依赖, 下层可以定义标准接口性质的.h
文件, 上层#include和调用标准.h, 下层在不修改标准.h的情况下进行升级修改, 或者完全替换为另一种实现.
同层模块可以相互#include.
目前考虑, 项目基础配置处于最底层L0. 硬件资源驱动处于L1, 基于硬件驱动提供的服务处于L2, 操作系统处于L3, 基于操作系统提供的服务处于L4, 具体应用处于L5.
按这种划分, 以灯为例, 作表如下:
层数 | 层名 | 功能模块 |
---|---|---|
L5 | 应用层 | 灯的逻辑功能 |
L4 | 系统服务层 | 系统Tick的时钟 |
L3 | 系统层 | RTOS |
L2 | 硬件服务层 | 驱动回调 |
L1 | 硬件驱动层 | Uart, Adc |
L0 | 配置层 |