ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

从零开始的DIY智能浇水应用

2021-10-18 14:02:48  阅读:177  来源: 互联网

标签:浇水 devid controller 从零开始 DIY error data 设备


前言

作为一个新世纪打工人,平常也会去养一些花草,来给我的房间增加点绿色和活力,但是常常因为工作忙而忘记一些事情。,毕竟我大部分的时间都是陪伴着电脑的(严正声明:我不是个单身狗!!!

(¬◡¬)✧),之前在淘宝上买了个土壤湿度传感器浇水设备,自己改造了一下,通过 WiFi 和 SDDC 成功接入了爱智盒子,现在准备搞一个爱智应用来进行设备的控制;

场景演示

先看一下我改造好的成品吧ヾ(๑╹◡╹)ノ",直接放在了我房间的展示柜上开始用了。

这是浇水器!
在这里插入图片描述
这是插进去的土壤湿度传感器的屁股!
在这里插入图片描述

(σ゚∀゚)σ..:*☆ 哎哟是不是很厉害啊!

这个花盆里面我插了之前的土壤湿度传感器和浇水器的出水口,然后浇水器的入水口我放在了一个装水的瓶子里,这样一个自动浇水的东西就完成了。因为这是我自己室内用的小设备,规模比较小,有想法的兄弟扩展扩展可以搞到在农业浇灌这方面去试试,想想还有点小兴奋呢。ヾ(>∀<)(ノ∀`●)⊃

应用演示

话不多说 ─=≡Σ(((つ•̀ω•́)つ,还是直接先看一下我的应用页面长什么样子,
在这里插入图片描述

一如既往的放了一个数据显示面板,一个设备选择模块,一个设备参数设置模块。

使用起来也是非常的简单,直接选择一下土壤湿度传感器以及浇水设备,拖动两个游标,设置浇水的适宜范围,每当我花盆里面的土壤湿度低于60%的时候就会通过 Spirit 向浇水器发送加水信号并开始加水,湿度达到85%就停止浇水,这样一个智慧浇水的场景就完成了。

整体实现逻辑是比较简单的,后面的话我也会逐步的在网上买一些其他的设备,搭建一些比较完整的智能场景出来。

代码分析

关于实现的代码也是利用了之前的设备模块 device,前端的我感觉就不用摆出来显摆了,比较简单的一个页面没啥好讲的,在这里插入图片描述

只贴一下后端js部分的关键代码吧<( ̄ ﹌  ̄)@m 。

// 因为用的频率比较高,个人比较懒,所以就基于正常的逻辑封装了一下,基本可以满足我目前乃至后面的大部分需求了,其他个别需求遇到再扩充。
// device_manager.js 
const Device = require('device');
const EventEmitter = require('events');

class DeviceManager extends EventEmitter {
  constructor() {
    super();
    this.devMap = new Map();
    this.controllerMap = new Map();
    this.init();
  }

  init() {
    // 获取当前所有已加入网络的在线设备!
    Device.list(true, (error, list) => {
      if (error) {
        console.error('Device.list error!' + error);
      } else {
        list.forEach((item) => {
          Device.info(item.devid, (error, info) => {
            if (error) {
              console.error('Device.info error!' + error);
            } else {
              this.devMap.set(item.devid, {
                devid: item.devid,
                alias: info.alias,
                report: info.report
              });
            }
          });
        });
      }
    });
    Device.on('join', async (devid, info) => {
      const dev = { devid, ...info };
      this.devMap.set(devid, dev);
      this.emit('join', dev);
    });
    Device.on('lost', (devid) => {
      const dev = this.devMap.get(devid);
      this.devMap.delete(devid);
      if (this.controllerMap.has(devid)) {
        this.controllerMap.delete(devid);
      }
      if (!dev) {
        this.emit('error', '应用出现未知错误,请退出重试!');
      } else {
        this.emit('lost', dev);
      }
    });
  }

  // 构建设备控制对象
  generateController(devid) {
    if (this.controllerMap.has(devid)) {
      return Promise.resolve(this.controllerMap.get(devid))
    }
    const controller = new Device();
    return new Promise((resolve, reject) => {
      controller.request(devid, (error) => {
        if (error) {
          reject(error);
        } else {
          this.controllerMap.set(devid, controller);
          resolve(controller);
        }
      });
    })
  }

  // 删除控制器
  deleteController(devid) {
    this.controllerMap.delete(devid);
  }

  // 发送设备消息
  sendDeviceInfo(devid, data) {
    const controller = this.controllerMap.get(devid);
    if (!controller) {
      return Promise.reject('程序出现未知错误,请退出重试!')
    }
    return new Promise((resolve, reject) => {
      controller.send(data, (err) => {
        if (err) {
          reject('控制设备失败,请重试!')
        } else {
          resolve();
        }
      }, 3)
    })
  }
}

const devManager = new DeviceManager();

module.exports = {
  devManager
}

以上就是封装的设备管理模块了,接下来在main.js中就会去使用该模块中的相关方法;

// main.js

...

function generateDevController(devid) {
	return new Promise((resolve, reject) => {
		const dev = devManager.devMap.get(devid);
		devManager.generateController(devid).then((controller) => {
			controller.on('message', (data) => {
				const points = humidity_water_scene.settings.points;
				if (isSceneDev(devid) && getDeviceType(dev) === 'humidity') {
					socketIO.emit('humidity', Number(data.data.soil_humidity.toFixed(1))); // 0-100
					if (!waterDev) {
						return;
					}
					if (data.data.soil_humidity < points[0] && !watering) {
						startWater(); // 浇水
					} else if (data.data.soil_humidity >= points[0] && watering) {
						stopWater(); // 停水
					}
				} else if (getDeviceType(dev) === 'water') {
					if (data.data.watering === 'ON' && watering && t === 0 && humidityDev) {
						setHumidityTimer(1000);
					} else if (data.data.watering === 'OFF' && !watering && t) {
						clearInterval(t);
						t = 0
					}
				}
			});
			resolve(controller);
		}).catch(() => {
			reject(`应用缺少控制${dev.alias}的权限!`);
		})
	})
}


...

上面的代码调用封装的设备管理模块实例的generateController方法来构造设备控制对象,

可以看到在设备消息监听事件 message 中如果湿度感应设备返回的数据值小于我们指定的值就会调用startWater方法进行浇水,否则就会停止浇水;

同样浇水设备会根据控制浇水开关命令,来返回当前设备状态,如果浇水设备处于运行中,则会主动加快获取湿度感应器的实时数值,便于实时控制设备。
在这里插入图片描述

总结

整体实现没有太大的问题,某些细节方面可能还需要优化一下,不过现在已经开始用了,当然肯定不会直接接到水龙头上,不然程序要是出bug了,那代价就有点太大了( uTェTu )!

今天的分享到此就结束了,具体的详细代码可以去灵感桌面的秘密宝库里面去查看,不说了,言尽于此,睡了。

标签:浇水,devid,controller,从零开始,DIY,error,data,设备
来源: https://www.cnblogs.com/inspiration-desktop/p/15420288.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有