最新消息:380元/半年,推荐全网最具性价比的一站式编程学习平台码丁实验室

NodeMcu 作为 MQTT 智能家居中的 TTS

Arduino 少儿编程 1581浏览 0评论

友情提示:380元/半年,儿童学编程,就上码丁实验室

本次应用使用 NodeMcu 连接讯飞的 XFS5152CE 语音合成芯片(开发板)并且连接一个小型功放作为 MQTT TTS 设备。除了 使用这种 TTS ,对于 HomeAssistant 来说,还有许多的 TTS 服务,如百度TTS、谷歌 TTS、微软 TTS ,之所以做这么一款设备,是因为这样可以实现一个纯局域网环境下的智能家居设备,当然也许还有其他好处,此处不表。

代码中使用的 GPIO 可通过下图进行进行查询。在此再次提醒诸位使用 Arduino IDE 为 NodeMcu 编程,NodeMcu 的引脚号与 GPIO 标号不一致。不要再出现明明程序是对的,引脚输出缺不正确这种情况了。

NodeMcu 作为 MQTT 智能家居中的 TTS

 

使用硬件:
MicroUSB 母头两个(作为供电接口)
NodeMcu(MQTT 订阅者,并且进行编码转换,将转换后的字符串以指定格式发送给 TTS 芯片)

Arduino Pro Mini

3MM 8*8点阵 1088BS

HC-SR505 迷你小型人体感应模块
科大讯飞 XFS5152CE 语音合成芯片(开发板)
小型功放板(注意输入电压,如果电压不是5.0V 则需要电源模块(升压模块))
4Ω 3W 喇叭两个(功放板要能推得动)
3.5 mm 音频接头公头一个
运行 HomeAssistant 服务设备
运行 MQTT 服务设备(也可将此服务与 HomeAssistant 安装在同一设备上,或者使用其他公司提供的 MQTT 服务器)

MQTT 设备接线图

以下为 NodeMcu 代码:

 

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <SoftwareSerial.h>

#define MQTT_VERSION MQTT_VERSION_3_1_1
#define iFlyTek_ResetPin 12
#define iFlyTek_RDYPin 14
#define WIFI_RX 5
#define WIFI_TX 4

// Wifi: SSID 和 密码
const char* WIFI_SSID = "YourWifiSSID"; //改成你的 WiFi 名称
const char* WIFI_PASSWORD = "YourWifiPassword"; //改成你的 WiFi 密码

// MQTT: ID, 服务端 IP, 端口号, 用户名 和 密码
const PROGMEM char* MQTT_CLIENT_ID = "ESP1";
const PROGMEM char* MQTT_SERVER_IP = "192.168.31.202"; //改成你的 MQTT 服务 IP 地址
const PROGMEM uint16_t MQTT_SERVER_PORT = 1883;  //改成你的 MQTT 服务端口号
const PROGMEM char* MQTT_USER = "YourMQTTUserName"; //改成你的 MQTT 服务用户名
const PROGMEM char* MQTT_PASSWORD = "YourMQTTUserPassword"; //改成你的 MQTT 服务密码

// MQTT: 主题
const char* MQTT_iFlyTek_TOPIC = "mqtt/ESP1/iFlyTek";
const char* MQTT_BodyState_TOPIC = "mqtt/ESP1/BodyState";
const char* MQTT_LED_TOPIC = "mqtt/ESP1/LEDInfo";

int bodySensor = 0;
long int lastSendTime, Now;
String BodyPubData = "{"BodyState":"BODY_STATE"}";

WiFiClient wifiClient;
PubSubClient client(wifiClient);
SoftwareSerial MySerial(softSerial_RX, softSerial_TX);

//芯片复位
void reset_iFlyTek()
{
  digitalWrite(iFlyTek_ResetPin, LOW);
  delay(50);
  digitalWrite(iFlyTek_ResetPin, HIGH);
}

//用来获取该字符在 UTF8 格式中占用的内存大小
int get_utf8_size(const char pInput)
{
  char c = pInput;
  if (c < 0x80) return 1;
  if (c >= 0x80 && c < 0xC0) return 0;
  if (c >= 0xC0 && c < 0xE0) return 2;
  if (c >= 0xE0 && c < 0xF0) return 3;
  return -1;
}

//获取整个字符数组以 UNICODE 编码时占用的大小
unsigned int get_output_size(char* ch, int size)
{
  unsigned int outSize = 0;
  char* input = ch;
  int inputPos = 0;
  while (inputPos < size)
  {
    int utf8Size = get_utf8_size(*input);
    if (utf8Size > 0)
    {
      outSize = outSize + 2;
      input = input + utf8Size;
      inputPos = inputPos + utf8Size;
    }
    else
    {
      outSize = 0;
      break;
    }
  }
  return outSize;
}

//以小端形式编码
//将单个 UTF8 编码的字符转换成以 UNICODE 编码
int utf8_to_unicode(const char* pInput, char *Unic)
{
  // b1 表示UTF-8编码的pInput中的高字节, b2 表示次高字节, ...
  char b1, b2, b3;

  *Unic = 0x0; // 把 *Unic 初始化为全零
  int utfbytes = get_utf8_size(*pInput);
  char *pOutput = Unic;
  switch ( utfbytes )
  {
    case 1:
      *pOutput = *pInput;
      *(pOutput + 1) = 0x00;
      utfbytes = 1;
      break;
    case 2:
      b1 = *pInput;
      b2 = *(pInput + 1);
      if ( (b2 & 0xE0) != 0x80 )
        return 0;
      *pOutput = (b1 << 6) + (b2 & 0x3F);
      *(pOutput + 1) = (b1 >> 2) & 0x07;
      break;
    case 3:
      b1 = *pInput;
      b2 = *(pInput + 1);
      b3 = *(pInput + 2);
      if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80) )
        return 0;
      *pOutput = (b2 << 6) + (b3 & 0x3F);
      *(pOutput + 1) = (b1 << 4) + ((b2 >> 2) & 0x0F);
      break;
    default:
      return 0;
      break;
  }
  return utfbytes;
}

void sendString(String string)
{
  int size = string.length();
  size =  size + 1;

  char buffer[size];
  string.toCharArray(buffer, size);
  char* input = buffer;
  size = size - 1;
  unsigned int outSize = get_output_size(buffer, size);
  if (outSize > 0)
  {
    char outCh[outSize];
    char* output = outCh;
    int inputPos = 0;
    while (inputPos < size)
    {
      int uft8Size = get_utf8_size(*input);
      if (uft8Size > 0)
      {
        utf8_to_unicode(input, output);
        output = output + 2;
        input = input + uft8Size;
        inputPos = inputPos + uft8Size;
      }
      else
      {
        break;
      }
    }
    unsigned char frameHeader = 0xFD;
    unsigned char temp = 0x00;
    unsigned int frameLength = outSize + 2;
    unsigned char dataHeader[2] = {0x01, 0x03};
    MySerial.write(frameHeader);
    if (frameLength < 255)
    {
      MySerial.write(temp);
    }
    MySerial.write(frameLength);
    MySerial.write(dataHeader[0]);
    MySerial.write(dataHeader[1]);
    for (int index = 0; index < outSize ; ++index)
    {
      MySerial.write(outCh[index]);
    }
  }
}

void dealLedData(String string)
{
  Serial.print(string);
}

// 接收来自 MQTT 的消息
void callback(char* p_topic, byte* p_payload, unsigned int p_length) {
  String payload;
  for (uint8_t i = 0; i < p_length; i++) {
    payload.concat((char)p_payload[i]);
  }

  // handle message topic
  if (String(MQTT_iFlyTek_TOPIC).equals(p_topic)) {
    sendString (payload);
  }
  else if (String(MQTT_LED_TOPIC).equals(p_topic)) {
    dealLedData (payload);
  }
}

void reconnect() {
  while (!client.connected()) {
    if (client.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD)) {
      delay(100);
      boolean sub_iFlyTek_OK = client.subscribe(MQTT_iFlyTek_TOPIC);
      boolean sub_LED_OK = client.subscribe(MQTT_LED_TOPIC);

      if (sub_LED_OK && sub_iFlyTek_OK)
        sendString(String("初始化成功"));
    } else {
      delay(5000);
    }
  }
}

void pushBodyState()
{
  Now = millis();
  if (Now - lastSendTime > 100) {
    BodyPubData = "{"BodyState":"BODY_STATE"}";
    bodySensor = digitalRead(Human1_DI);
    switch (bodySensor)
    {
      case 1:
        BodyPubData.replace("BODY_STATE", "Yes");
        break;
      case 0:
        BodyPubData.replace("BODY_STATE", "No");
        break;
      default:
        BodyPubData.replace("BODY_STATE", "No");
    }
    client.publish(MQTT_BodyState_TOPIC, BodyPubData.c_str(), true);
    lastSendTime = Now;
  }
}

void setup() {
  Serial.begin(9600);
  MySerial.begin(9600);

  pinMode(iFlyTek_ResetPin, OUTPUT);
  pinMode(Human1_DI, INPUT);

  reset_iFlyTek();

  delay(100);
  sendString(String("正在初始化,请稍后"));
  delay(100);
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
  }

  client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);
  client.setCallback(callback);

  Now = millis();
  lastSendTime = Now;
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  pushBodyState();

}

 

Arduino Pro mini 代码:

#include <FrequencyTimer2.h>

//嘴巴
#define OPEN1 { 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {0, 0, 1, 1, 1, 1, 0, 0}, 
    {0, 1, 0, 0, 0, 0, 1, 0}, 
    {1, 0, 0, 0, 0, 0, 0, 1}, 
    {1, 0, 0, 0, 0, 0, 0, 1}, 
    {0, 1, 0, 0, 0, 0, 1, 0}, 
    {0, 0, 1, 1, 1, 1, 0, 0}, 
    {0, 0, 0, 0, 0, 0, 0, 0} 
  }

#define OPEN2 { 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {0, 1, 1, 1, 1, 1, 1, 0}, 
    {1, 0, 0, 0, 0, 0, 0, 1}, 
    {1, 0, 0, 0, 0, 0, 0, 1}, 
    {0, 1, 1, 1, 1, 1, 1, 0}, 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {0, 0, 0, 0, 0, 0, 0, 0} 
  }

#define CLOSE { 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {1, 1, 1, 1, 1, 1, 1, 1}, 
    {1, 1, 1, 1, 1, 1, 1, 1}, 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {0, 0, 0, 0, 0, 0, 0, 0} 
  }

//天气
#define w_good { 
    {0, 1, 0, 0, 0, 1, 0, 0}, 
    {1, 0, 1, 0, 1, 0, 1, 0}, 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {1, 0, 0, 0, 0, 0, 1, 0}, 
    {0, 1, 0, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 1, 1, 0, 0, 0} 
  }

#define w_bad { 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {1, 1, 1, 0, 1, 1, 1, 0}, 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {0, 0, 1, 1, 1, 0, 0, 0}, 
    {0, 1, 0, 0, 0, 1, 0, 0}, 
    {1, 0, 0, 0, 0, 0, 1, 0} 
  }

//数字
#define num_0 { 
    {0, 0, 1, 1, 1, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 1, 1, 1, 0, 0} 
  }

#define num_1 { 
    {0, 0, 0, 1, 0, 0, 0, 0}, 
    {0, 0, 0, 1, 0, 0, 0, 0}, 
    {0, 0, 0, 1, 0, 0, 0, 0}, 
    {0, 0, 0, 1, 0, 0, 0, 0}, 
    {0, 0, 0, 1, 0, 0, 0, 0}, 
    {0, 0, 0, 1, 0, 0, 0, 0}, 
    {0, 0, 0, 1, 0, 0, 0, 0}, 
    {0, 0, 0, 1, 0, 0, 0, 0} 
  }

#define num_2 { 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {0, 0, 1, 1, 1, 1, 0, 0}, 
    {0, 0, 0, 0, 0, 1, 0, 0}, 
    {0, 0, 0, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 1, 1, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 0, 0, 0}, 
    {0, 0, 1, 0, 0, 0, 0, 0}, 
    {0, 0, 1, 1, 1, 1, 0, 0} 
  }

#define num_3 { 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {0, 0, 1, 1, 1, 1, 0, 0}, 
    {0, 0, 0, 0, 0, 1, 0, 0}, 
    {0, 0, 0, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 1, 1, 1, 0, 0}, 
    {0, 0, 0, 0, 0, 1, 0, 0}, 
    {0, 0, 0, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 1, 1, 1, 0, 0} 
  }

#define num_4 { 
    {0, 0, 0, 0, 1, 0, 0, 0}, 
    {0, 0, 0, 1, 1, 0, 0, 0}, 
    {0, 0, 1, 0, 1, 0, 0, 0}, 
    {0, 1, 0, 0, 1, 0, 0, 0}, 
    {0, 1, 1, 1, 1, 1, 0, 0}, 
    {0, 0, 0, 0, 1, 0, 0, 0}, 
    {0, 0, 0, 0, 1, 0, 0, 0}, 
    {0, 0, 0, 0, 1, 0, 0, 0} 
  }

#define num_5 { 
    {0, 0, 0, 0, 0, 0, 0, 0}, 
    {0, 0, 1, 1, 1, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 0, 0, 0}, 
    {0, 0, 1, 0, 0, 0, 0, 0}, 
    {0, 0, 1, 1, 1, 0, 0, 0}, 
    {0, 0, 0, 0, 0, 1, 0, 0}, 
    {0, 0, 0, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 1, 1, 1, 0, 0} 
  }

#define num_6 { 
    {0, 0, 1, 1, 1, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 0, 0, 0}, 
    {0, 0, 1, 0, 0, 0, 0, 0}, 
    {0, 0, 1, 0, 0, 0, 0, 0}, 
    {0, 0, 1, 1, 1, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 1, 1, 1, 0, 0} 
  }

#define num_7 { 
    {0, 0, 1, 1, 1, 1, 0, 0}, 
    {0, 0, 0, 0, 0, 1, 0, 0}, 
    {0, 0, 0, 0, 0, 1, 0, 0}, 
    {0, 0, 0, 0, 0, 1, 0, 0}, 
    {0, 0, 0, 0, 0, 1, 0, 0}, 
    {0, 0, 0, 0, 0, 1, 0, 0}, 
    {0, 0, 0, 0, 0, 1, 0, 0}, 
    {0, 0, 0, 0, 0, 1, 0, 0} 
  }

#define num_8 { 
    {0, 0, 1, 1, 1, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 1, 1, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 1, 1, 1, 0, 0} 
  }

#define num_9 { 
    {0, 0, 1, 1, 1, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 1, 1, 1, 0, 0}, 
    {0, 0, 0, 0, 0, 1, 0, 0}, 
    {0, 0, 0, 0, 0, 1, 0, 0}, 
    {0, 0, 1, 1, 1, 1, 0, 0} 
  }


//#define pin_body 19
#define pin_TTS 3

byte col = 0;
byte leds[8][8];
bool readySpeak = true;

String strRecv = "";
long now = 0;
long lastRecv = 0;
long lastTTS = 0;
long lastWeather = 0;
long lastTime = 0;
short lastTTSIndex = 0;
short lastTimeIndex = 0;


bool newDataComing = false;

bool weatherRecvOK = false;
bool timeRecvOK = false;

short weatherIndex = -1;
short timeArray[4] = { -1, -1, -1, -1};

const short pins[16] = {5, 4, 19, 18, 14, 15, 16, 17, 13, 12, 11, 10, 9, 8, 7, 6 };
const short rows[8] = {pins[15], pins[14], pins[10], pins[5], pins[9], pins[3], pins[2], pins[12]};
const short cols[8] = {pins[8], pins[13], pins[7], pins[11], pins[0], pins[6], pins[1], pins[4]};

const PROGMEM int numPatterns = 4;
//const PROGMEM byte patterns[numPatterns][8][8] = { CLOSE, OPEN2, OPEN1, OPEN2 };
byte patterns[numPatterns][8][8] = { CLOSE, OPEN2, OPEN1, OPEN2 };

byte weatherCondition[2][8][8] = { w_good, w_bad };

byte Time_serial[10][8][8] = {
  num_0 , num_1 , num_2 , num_3 , num_4 , num_5 , num_6 , num_7 , num_8 , num_9
};


void setup() {
  Serial.begin(9600);
  for (int i = 0; i < 16; i++) {
    pinMode(pins[i], OUTPUT);
  }

  // set up cols and rows
  for (int i = 1; i <= 8; i++) {
    digitalWrite(cols[i - 1], LOW);
    digitalWrite(rows[i - 1], LOW);
  }

  pinMode(pin_TTS, INPUT);

  clearLeds();

  FrequencyTimer2::disable();
  FrequencyTimer2::setPeriod(2000);
  FrequencyTimer2::setOnOverflow(display);

  now = millis();
  lastRecv = now;
  lastTTS = now;
  lastWeather = now;
  lastTime = 0;
  lastTTSIndex = 0;
  lastTimeIndex = 0;

}

void recvWeatherTime()
{
  if (Serial.available() > 0) {
    char str = char(Serial.read());
    strRecv = strRecv + str;
    lastRecv = millis();
    newDataComing = true;
    timeRecvOK = false;
    weatherRecvOK = false;
    delay(2);
  }
  else {
    now = millis();
    if ((newDataComing == true) && (now - lastRecv > 100)) {
      int index = strRecv.indexOf(",");
      if (-1 != index)
      {
        String _weather = strRecv.substring(0, index);
        _weather.replace("weather:", "");
        _weather.replace(",", "");
        _weather.replace(" ", "");
        if (_weather.equals("clear-night"))
          weatherIndex = 0;
        else if (_weather.equals("cloudy"))
          weatherIndex = 0;
        else if (_weather.equals("fog"))
          weatherIndex = 1;
        else if (_weather.equals("hail"))
          weatherIndex = 1;
        else if (_weather.equals("lightning"))
          weatherIndex = 1;
        else if (_weather.equals("lightning-rainy"))
          weatherIndex = 1;
        else if (_weather.equals("partlycloudy"))
          weatherIndex = 0;
        else if (_weather.equals("pouring"))
          weatherIndex = 1;
        else if (_weather.equals("rainy"))
          weatherIndex = 1;
        else if (_weather.equals("snowy"))
          weatherIndex = 1;
        else if (_weather.equals("snowy-rainy"))
          weatherIndex = 1;
        else if (_weather.equals("sunny"))
          weatherIndex = 0;
        else if (_weather.equals("windy"))
          weatherIndex = 1;
        else if (_weather.equals("windy-variant"))
          weatherIndex = 0;
        else if (_weather.equals("exceptional"))
          weatherIndex = 0;
        else
          weatherIndex = -1;

        if ((weatherIndex >= 0) && (weatherIndex < 2))
          weatherRecvOK = true;

        String _timeString = strRecv.substring(index + 1);
        _timeString.replace("time:", "");
        _timeString.replace(":", "");
        _timeString.replace(",", "");
        _timeString.replace(" ", "");
        String s_hour = _timeString.substring(0, 2);
        int hour = s_hour.toInt();
        String s_minute = _timeString.substring(2);
        int minute = s_minute.toInt();
        if ((hour >= 0 && hour < 24) && (minute >= 0) && (minute <= 59))
        {
          timeArray[0] = hour / 10 ;
          timeArray[1] = hour % 10 ;
          timeArray[2] = minute / 10 ;
          timeArray[3] = minute % 10 ;
          timeRecvOK = true;
        }
      }
      strRecv = "";
      newDataComing = false;
    }
  }
}

void loop() {
  recvWeatherTime();

  bool TTSState = digitalRead(pin_TTS);
  //  bool TTSState = true;
  if (TTSState)
  {
    //    FrequencyTimer2::setOnOverflow(display);
    now = millis();
    if (now - lastTTS > 500)
    {
      if (lastTTSIndex >= numPatterns)
        lastTTSIndex = 0;
      setPatternTTS(lastTTSIndex);
      FrequencyTimer2::setOnOverflow(display);
      lastTTS = now;
      lastTTSIndex ++;
      lastTime = now;
      lastWeather = now;
    }
    lastTimeIndex = 0;
  }
  else
  {
    lastTTSIndex = 0;
    if (timeRecvOK && weatherRecvOK)
    {
      now = millis();
      if (lastTimeIndex < 4)
      {
        setPatternTime(lastTimeIndex);
        FrequencyTimer2::setOnOverflow(display);
        lastWeather = now;
        if ((now - lastTime) > 1000)
        {
          lastTime = now;
          lastWeather = now;
          lastTimeIndex ++;
        }
      }
      else
      {
        FrequencyTimer2::setOnOverflow(display);
        setPatternWeather(weatherIndex);
        if (now - lastWeather > 5000)
        {
          lastTimeIndex = 0;
          timeRecvOK = false;
          weatherRecvOK = false;
          clearLeds();
          FrequencyTimer2::setOnOverflow(0);
        }
      }
    }
    else
    {
      FrequencyTimer2::setOnOverflow(0);
      clearLeds();
      display();
      now = millis();
      lastTime = now;
    }
  }
}

void clearLeds() {
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      leds[i][j] = 0;
    }
  }
}

void setPatternWeather(int pattern) {
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      leds[i][j] = weatherCondition[pattern][i][j];
    }
  }
}
void setPatternTime(int pattern) {
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      short index = timeArray[pattern];
      leds[i][j] = Time_serial[index][i][j];
    }
  }
}
void setPatternTTS(int pattern) {
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      leds[i][j] = patterns[pattern][i][j];
    }
  }
}

// Interrupt routine
void display() {
  digitalWrite(cols[col], LOW);  // Turn whole previous column off
  col++;
  if (col == 8) {
    col = 0;
  }
  for (int row = 0; row < 8; row++) {
    if (leds[col][7 - row] == 1) {
      digitalWrite(rows[row], LOW);  // Turn on this led
    }
    else {
      digitalWrite(rows[row], HIGH); // Turn off this led
    }
  }
  digitalWrite(cols[col], HIGH); // Turn whole column on at once (for equal lighting times)
}

 

HomeAssistant 配置:

 

weather:
  - platform: yweather
    woeid: 2151849

binary_sensor:
  - platform: mqtt
    state_topic: "mqtt/ESP1/BodyState"
    name: 'TTS_BodyState'
    payload_on: "Yes"
    payload_off: "No"
    device_class: motion
    value_template: '{{ value_json.BodyState }}'

sensor:
  - platform: time_date
    display_options:
      - 'date_time'
      - 'time'
      - 'date'

  - platform: template
    sensors:
      template_arduino_motion:
        friendly_name: "TTS 人体传感器"
        value_template: "{% if is_state('binary_sensor.tts_bodystate', 'on') %}有人{% else %}无人{% endif %}"

input_text:
  iflytek:
    name: iFlyTek
    min: 0
    max: 5000

mqtt:
#改成你的 MQTT 服务端口号
  broker: 192.168.31.202
#改成你的 MQTT 服务端口号
  port: 1883
#改成你的 MQTT 服务用户名
  username: YourMQTTUserName
#改成你的 MQTT 服务密码
  password: YourMQTTUserPassword

automation: !include automations.yaml

 

automations.yaml 文件:

 

- id: iFlyTek
  alias: iFlyTekTTS
  trigger:
    platform: state
    entity_id: input_text.iflytek
  action:
    service: mqtt.publish
    data_template:
      topic: "mqtt/ESP1/iFlyTek"
      payload: "{{states.input_text.iflytek.state}}"

- id: Someone
  alias: SomeoneInFront
  trigger:
  - entity_id: binary_sensor.tts_bodystate
    from: 'off'
    platform: state
    to: 'on'
  action:
    service: mqtt.publish
    data_template:
      topic: "mqtt/ESP1/LEDInfo"
      payload: "weather:{{states('weather.yweather')}},time:{{states('sensor.time')}}"

 

后续我会将 Arduino 代码封装成库,方便直接调用。这个坑留着以后填。

 

实际效果图:

NodeMcu 作为 MQTT 智能家居中的 TTS

 

自己做了个小盒子把一堆零件装在这个小盒子里。

HomeAssistant 输入框输入内容后,TTS 播放该内容,同时显示一下时间和天气(好与坏,笑脸与哭脸表示)。或者其他任何方式通过MQTT协议发送该主题的内容,TTS也可以播放。

当人体传感器的状态从无人到有人后,LED 点阵显当前时间(每个数字 1 秒),之后根据天气状况显示五秒的哭脸或者笑脸。

当然这种方式的 TTS 播报效果跟百度的在线 TTS 效果差很多。

您必须 登录 才能发表评论!