【转载】基于M5StickC的智能马桶遥控器-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2920|回复: 0

【转载】基于M5StickC的智能马桶遥控器

[复制链接]
发表于 2019-10-17 10:15 | 显示全部楼层 |阅读模式
    智能马桶是个好东西,上面有各种各样舒服的功能,通常配有一个遥控器,为了以防遥控器哪天坏掉又没法单独配,利用M5StickC来提前做一个遥控器备份。由于M5StickC只具备IR发射功能,因此使用IR unit先来对遥控器编码进行读取,通过IRremote8266这个库找到IRrecvDumpV2这个示例,先按示例获取到遥控码,再通过sendRaw进行发送。
https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_133064_effd5001-6392.jpeg

运行环境准备:
M5StickC马桶型号
  • TOTO NEOREST AH3

遥控信号
以下信号数据是对实际遥控信号的分析。按下按钮时,每个信号重复发送3次。
[td]
功能
信号1
信号2
马桶盖开关
0x2008000E0E
-

坐垫开关
0x200800F6F6
-

0x200800B0B0
-

0x2008008888
-

eco 小
0x200800B6B6
-

臀洗
0x2008006060
0x2008AC802C
注1、2
轻柔
0x2008006060
0x2008ACA804
注1、2
冲洗
0x2008001010
0x2008AC40EC
注1、2
停止
0x2008000000
0x2008AADA70
注1
按摩
0x200800E0E0
-

干燥
0x200800C0C0

-

注3
去臭
0x2008007C7C
-


注1:“ 臀洗 / 轻柔 /冲洗/ 停止”按钮输出两种信号:“ Move On / Off”和“ Wash”。注2:实际的遥控器处于一种状态,如果在洗涤停止时按“臀洗/轻柔/冲洗”,则仅发送信号2(洗涤),而在洗涤时按信号,则发送信号1(“移动开/关”)。信号2(清洁)都被发送,并且由于该实施方式没有实际问题,所以信号1和信号2都总是被发送。
注3:遥控器还具有干燥状态,如果在干燥过程中再次按下“干燥”按钮,将发送与“停止”相同的信号。

实例
连接了连接到M5StickC的IR REMOTE单元以进行遥控器的红外信号分析,使用接收针脚编号33执行IRrecvDumpV2
https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_133064_41d0b793-9ac2.jpeg
远程控制程序将发送信号作为菜单显示在屏幕上,并通过按钮操作进行选择和发送。
https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_133064_d2589814-9163.jpeg
使用按钮B /电源按钮前进/返回菜单项
使用按钮A发送选择的信号

M5StickC程序
[mw_shl_code=arduino,true]#include <M5StickC.h>
#include <Arduino.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>

const uint16_t kIrLed = 9;  // M5StickC GPIO pin to use.
IRsend irsend(kIrLed);  // Set the GPIO to be used to sending the message.

// IR Data for TOTO Washlet Neorest AH3
struct {
  std::string name;
  uint64_t data1;
  uint64_t data2;
} ir_data[] = {
    {"Op/Cl Lid",  0x2008000E0E, 0},            // Open Close Lid
    {"Op/Cl Seat", 0x200800F6F6, 0},            // Open Close Seat
    {"Full Flush", 0x200800B0B0, 0},            // Full Flush
    {"Half Flush", 0x2008008888, 0},            // Half Flush
    {"eco Flush",  0x200800B6B6, 0},            // eco Half Flush
    {"Wash Rear",  0x2008006060, 0x2008AC802C}, // move on/off + Wash Rear
    {"Soft Rear",  0x2008006060, 0x2008ACA804}, // move on/off + Soft Rear
    {"Bidet",      0x2008001010, 0x2008AC40EC}, // move on/off + Bidet
    {"Stop",       0x2008000000, 0x2008AADA70}  // move off + Stop Wash
  };

int data_count = sizeof(ir_data) / sizeof(ir_data[0]);
int ix = 0;
int x_offset0 =  3;
int x_offset1 =  5;
int x_offset2 = 15;
int y_offset1 = 12;
int y_offset2 = 30;
int height    = 14;

void sendToto(uint64_t data) {
  irsend.sendGeneric(
          6000,  3000,      // headermark, headerspace,
          600,   1600,      // onemark,    onespace,
          600,    600,      // zeromark,   zerospace,
          600,  40000,      // footermark, gap,
          data,    39,      // data,       nbits,
          38,    true,      // frequency,  MSBfirst,
          2, kDutyDefault); // repeat,     dutycycle (kDutyDefault = 50 %)
}

void setup() {
  M5.begin();
  irsend.begin();

  M5.Axp.ScreenBreath(9); // Brightness (7-15)
  M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);
  M5.Lcd.drawString("<< Washlet >>", x_offset0, y_offset1);
  M5.Lcd.setTextColor(TFT_ORANGE, TFT_BLACK);
  M5.Lcd.drawString(">", x_offset1, y_offset2);
  M5.Lcd.drawString(ir_data[0].name.c_str(), x_offset2, y_offset2);
  M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);
  for (int i = 1; i < data_count; i ++) {
    M5.Lcd.drawString(ir_data.name.c_str(), x_offset2, y_offset2 + i * height);   
  }
}

void loop() {
  M5.update();

  if (M5.BtnA.wasPressed()) {
    Serial.println(ir_data[ix].name.c_str());
    sendToto(ir_data[ix].data1);
    if (ir_data[ix].data2 != 0) {
      delay(40);
      sendToto(ir_data[ix].data2);
    }
  }

  if (M5.BtnB.wasPressed() || M5.Axp.GetBtnPress() > 0) {
    M5.Lcd.setTextColor(TFT_BLACK, TFT_BLACK);
    M5.Lcd.drawString(">",  x_offset1, y_offset2 + ix * height);
    M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);
    M5.Lcd.drawString(ir_data[ix].name.c_str(), x_offset2, y_offset2 + ix * height);
    if (M5.BtnB.wasPressed()) {
      ix ++;
      if (ix == data_count) {
        ix = 0;
      }
    } else {
      ix --;
      if (ix < 0) {
        ix = data_count - 1;
      }      
    }
    M5.Lcd.setTextColor(TFT_ORANGE, TFT_BLACK);
    M5.Lcd.drawString(">",  x_offset1, y_offset2 + ix * height);
    M5.Lcd.drawString(ir_data[ix].name.c_str(), x_offset2, y_offset2 + ix * height);   
  }
}[/mw_shl_code]

遥控信号分析程序
该程序分析IRrecvDumpV2采集的原始数据,并将其转换为信号数据。我用Python编写了它,然后在Mac上运行了它,但是看起来像这样,因此可以将其合并到IRrecvDumpV2中。在不确认规格等的情况下,根据实际值调整值范围的判断值。
[mw_shl_code=python,true]import re
import fileinput

HDR_MARK   =  6000
HDR_SPACE  =  3000
BIT_MARK   =   600
ZERO_SPACE =   600
ONE_SPACE  =  1600
GAP        = 40000

for line in fileinput.input():
    line = line.strip()
    if len(line) == 0:
        continue

    m = re.match('uint16_t rawData\[\d+\] = {([^}]+)};', line)
    if m:
        print(line)
        print()
        raw = list(map(lambda x: int(x), m.group(1).split(',')))
        while len(raw) >= 2:
            mark  = raw.pop(0) # Skip Header Mark
            space = raw.pop(0) # Skip Header Space
            data = 0
            bit_length = 0
            while len(raw) >= 2:
                mark  = raw.pop(0)
                space = raw.pop(0)
                if (BIT_MARK-200) <= mark <= (BIT_MARK+200):
                    if (ZERO_SPACE-200) <= space <= (ZERO_SPACE+200):
                        print('0', end='')
                        data = data << 1
                        bit_length += 1
                    elif (ONE_SPACE-200) <= space <= (ONE_SPACE+200):
                        print('1', end='')
                        data = data << 1 | 1
                        bit_length += 1
                    elif (GAP-10000) < space < (GAP+10000):
                        break
                    else:
                        print()
                        print('Space Error:', space)
                else:
                    print()
                    print('BitMark Error:', mark)
            print('  0x{:X}  {:d} bit'.format(data, bit_length))
        print()[/mw_shl_code]

这是通过使用上述程序处理“马桶盖打开/关闭”按钮的原始数据来确认输出3次0x2008000E0E信号的示例。
[mw_shl_code=python,true]$ python TOTO_Washlet.py Raw_Data.txt
uint16_t rawData[245] = {5984, 2958,  606, 544,  580, 1658,  582, 544,  574, 544,  576, 544,  582, 540,  576, 544,  576, 544,  576, 544,  578, 516,  604, 546,  576, 1662,  576, 544,  578, 520,  600, 546,  578, 544,  578, 544,  578, 542,  578, 546,  578, 542,  580, 542,  576, 520,  600, 544,  576, 548,  578, 544,  576, 544,  578, 520,  602, 1658,  578, 1636,  602, 1636,  600, 546,  578, 544,  576, 544,  578, 544,  576, 544,  578, 1662,  576, 1636,  602, 1660,  578, 546,  578, 39116,  5960, 2960,  602, 546,  578, 1636,  600, 522,  604, 540,  580, 518,  602, 544,  578, 544,  578, 544,  576, 544,  576, 544,  578, 522,  600, 1634,  604, 518,  602, 518,  602, 548,  574, 548,  574, 544,  578, 544,  576, 546,  576, 544,  578, 544,  580, 516,  602, 548,  576, 544,  578, 546,  576, 544,  578, 542,  578, 1660,  580, 1632,  602, 1660,  576, 544,  578, 546,  576, 518,  604, 544,  578, 546,  574, 1658,  582, 1656,  578, 1662,  576, 544,  578, 38872,  5984, 2958,  604, 520,  604, 1636,  602, 542,  578, 544,  576, 546,  576, 520,  602, 542,  578, 522,  604, 542,  578, 544,  576, 550,  572, 1634,  604, 562,  576, 544,  578, 544,  578, 546,  576, 548,  578, 544,  576, 546,  574, 544,  576, 544,  578, 546,  578, 542,  578, 544,  576, 522,  600, 546,  578, 544,  578, 1634,  602, 1660,  578, 1660,  576, 544,  576, 548,  572, 544,  576, 546,  578, 544,  576, 1660,  578, 1636,  602, 1658,  578, 544,  578};  // UNKNOWN 450EA3E

010000000001000000000000000111000001110  0x2008000E0E  39 bit
010000000001000000000000000111000001110  0x2008000E0E  39 bit
010000000001000000000000000111000001110  0x2008000E0E  39 bit[/mw_shl_code]
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-12-28 09:47 , Processed in 0.079453 second(s), 19 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表