我正在参与「创意开发 投稿大赛」概况请看:掘金创意开发大赛来了!

布景

这是咱们家的主子可爱粘人

给主子做了个小玩具

每天不是吃便是睡日子过的好不安闲。

但是每当我想进步的时候它就会躺在我键盘上

给主子做了个小玩具

猫子果然是人类进步的绊脚石!

为了解决这个问题我决定给小猫咪做个下玩具能够让它来挤我键盘的时候让它自己玩去。

分析

小猫咪喜欢什么?

  1. 盒子 对盒子肯定是真爱有盒必进
  2. 好奇心 对一些声响很灵敏,听到后会比较振奋要去一探终究
  3. 窗外的小鸟那也是真爱要是有小鸟那必须蹲着看
  4. 它平常还经常玩一些毛绒小球

还有便是它对任何玩具都只要必定的新鲜度,如果比较机械一般几天就不爱玩了 依据分析大致规划了这么一个玩具 在一个盒子里 放上一些毛绒小球,在盒子里开一些孔方便它用爪子伸进来抓取,同时盒子里面需要有一个发声装置比如能够播映小鸟的叫声,这声响能够替换,当它对当时声响不灵敏后能够替换些新的声响,同时咱们能够监听猫子的爪子伸入然后触发调大音量或许更尖锐的声响模拟出遭受进犯

玩具的名字就叫 BirdBox

规划调研

盒子 先随意找个快递盒子随意开几个口子完结。

毛绒小球 刚好我有之前买的毛绒小球

给主子做了个小玩具

放在一起

给主子做了个小玩具

接下去是要开发的部分了 发声装置

咱们能够运用一个mcu操控一个小喇叭来完结发声

硬件部分

esp8266 和小喇叭

给主子做了个小玩具

给主子做了个小玩具

选用github.com/earlephilho… 库即可播映声响 文档里用NPN三极管即可驱动,我这个带有8002B功放芯片也也没有问题

服务端

预备选用 Nestjs nestjs.com/

MQTT 服务器 emqx github.com/emqx/emqx

手机端

选用微信小程序开发

整体架构

设备端经过MQTT和云端保持通讯,App端则经过HTTP和服务端保持通讯

给主子做了个小玩具

原型Demo开发

服务端完结

结构装置参阅官方文档吧nestjs.com/

脚手架创立工程

nest new server

选用TypeOrm github.com/typeorm/typ… 作为数据库结构

app.module.ts 的 module中装备运用 sqlite 作为数据库,没多多少数据 sqlite 正合适~

TypeOrmModule.forRoot({
    type: 'sqlite',
    database: 'sqlite.db',
    autoLoadEntities: true,
    synchronize: true,
  })

完结一个简单的curd 这儿一个设备为例子

定义数据实体相当于表结构 device.entity.ts

import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
@Entity()
export class Device {
    @PrimaryGeneratedColumn()
    id: number;
    @Column()
    name: string;
    @Column()
    serial: string;
    @Column()
    desc: string;
}

然后在service 进行 curd 操作, 首先是在构造函数中注入 deviceRespository 然后运用它做相应的操作啦

@Injectable()
export class DeviceService {
  constructor(
    @InjectRepository(Device) private deviceRespository: Repository<Device>,
  ) {}
  create(createDeviceDto: CreateDeviceDto) {
    return this.deviceRespository.save(createDeviceDto);
  }
  findOne(id: number) {
    return this.deviceRespository.findOneBy({ id });
  }
  update(id: number, updateDeviceDto: UpdateDeviceDto) {
    return this.deviceRespository.update(id, updateDeviceDto);
  }
  remove(id: number) {
    // return this.deviceRespository.remove();
  }
}

详细仍是看官网吧

MQTT服务

依据 emqx 开源版别 github.com/emqx/emqx

直接 docker 布置服务

docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 8883:8883 -p 18083:18083 emqx/emqx:latest

服务端口布置在 1883, 操控台端口在 18083 默许账号 admin 默许暗码public

nestjs 连上 Mqtt 服务

装置mqtt module

npm install nest-mqtt mqtt --save

app.module.ts 中装备好mqtt服务

 MqttModule.forRoot({
      host: 'localhost',
      port: 1883,
      queue: true,
    })
  ],

监听和发布音讯 在构造中注入 mqttService 能够用它完结publish操作,监听则能够运用 @Subscribe 装饰器完结

@Injectable()
export class AppService {
  constructor(@Inject(MqttService) private readonly mqttService: MqttService) {}
  getHello(): string {
    return 'Hello World!';
  }
  @Subscribe('test')
  test(@Payload() payload) {
    console.log("subscribe")
    console.log(payload)
  }
  publish() : string {
    this.mqttService.publish('play', {play: "on"});
    return 'publish'
  }
}

至此咱们已经能够完结经过发Http恳求来触发一个mqtt音讯了,也就能够完结经过手机端发送恳求来达到操控设备端了

硬件

依据Arduino开发

配网

直接运用 WiFiManager github.com/tzapu/WiFiM… 即可完结配网,不过作为demo原型 直接暂时写死 ssid & password 即可

在setup 函数中

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

MQTT 完结

依据 AsyncMqttClient github.com/marvinroger…


//初始化
void initMqtt(const char* clientId, OnMqttConnect connect, OnMqttMessage onMsg) {
    onConnect = connect;
    onMessage = onMsg;
    mqttClient.setClientId(clientId);
    mqttClient.onConnect(_onMqttConnect);
    mqttClient.onDisconnect(onMqttDisconnect);
    mqttClient.onSubscribe(onMqttSubscribe);
    mqttClient.onUnsubscribe(onMqttUnsubscribe);
    //注册音讯回调
    mqttClient.onMessage(_onMqttMessage);
    mqttClient.onPublish(onMqttPublish);
    mqttClient.setServer(MQTT_HOST, PORT);
    mqttClient.setMaxTopicLength(512);
    mqttClient.setKeepAlive(60);
    mqttClient.connect();
}
// 收到音讯
void _onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
  Serial.println("Publish received.");
  Serial.print("  topic: ");
  Serial.println(topic);
  Serial.print("  qos: ");
  Serial.println(properties.qos);
  Serial.print("  dup: ");
  Serial.println(properties.dup);
  Serial.print("  retain: ");
  Serial.println(properties.retain);
  Serial.print("  len: ");
  Serial.println(len);
  Serial.print("  index: ");
  Serial.println(index);
  Serial.print("  total: ");
  Serial.println(total);
  onMessage(topic, payload, properties, len, index, total);
}
//运用来注册监听
mqttClient.subscribe(topic)

至此咱们就能够让运用经过MQTT来操控 咱们的模块啦

播映声响

首先是接线地和电源没什么好说的数据线要和RX接也便是D8边上的那个 如图接好~

给主子做了个小玩具

依据github.com/earlephilho… 该库文档它不只支持 SPIFFS 经过文件播映 还支持 http 流播映 这儿咱们暂时选用文件播映 后续考虑是否要切成用http流播映,直接依据它的样例代码即可完结音乐播映

  file = new AudioFileSourceSPIFFS("/bird.mp3");
  id3 = new AudioFileSourceID3(file);
  id3->RegisterMetadataCB(MDCallback, (void*)"ID3TAG");
  out = new AudioOutputI2SNoDAC();
  mp3 = new AudioGeneratorMP3();
  mp3->begin(id3, out);

bird.mp3文件只需放到工程文件的data文件夹下上传时就会上传了

至此咱们已经完结了所有根底功用。

测验

总算到了激动人心的测验环节,测验喵也已经预备好了,因为不能插入视频这儿只能看看图片了,效果挺好!成功的引起了两个测验的好奇~

给主子做了个小玩具

测验视频能够移步B站查看 www.bilibili.com/video/BV1wd…

后续

完善小程序功用能够挑选声响列表,能够定时触发等功用

给主子做了个小玩具

当时只要部分后端片段代码放在这儿 github.com/6a209/birdb… 后续会更新上设备端和小程序端相关代码。