LoginSignup
9
2

More than 3 years have passed since last update.

enebularで、ATOM Echoにツイートを喋らせる!

Last updated at Posted at 2020-12-20

ATOM Echoにツイートを喋らせてみました!
ぬいぐるみにうめこんだら、いい感じになりそう。

enebularでツイートを取得し、テキストをMQTTで送信、最後にATOM Echoで再生します。
MQTTブローカーはshiftr.ioを使用しました。

Atom echo側のコード

はじめはUIFlowでやろうと試みたのですが、M5burnerでATOM Echo TTSのtoken取得ができず断念...

こちらの記事を参考にさせていただきました!
ATOM Echo でTTSを堪能
M5StackとNode-REDをMQTTで連携するメモ

//*-----------------------------------*
// ボード: M5Stick-C
// Upload Speed: 115200
//*-----------------------------------*

#include "M5Atom.h"
#include <WiFi.h>
#include <WiFiClient.h>
#include <PubSubClient.h>
#include <google-tts.h>

#include "AudioFileSourceICYStream.h"
#include "AudioFileSourceBuffer.h"
#include "AudioGeneratorMP3.h"
#include "AudioOutputI2S.h"

#define CONFIG_I2S_BCK_PIN      19
#define CONFIG_I2S_LRCK_PIN     33
#define CONFIG_I2S_DATA_PIN     22

// Wi-FiのSSID
char *ssid = "";
// Wi-Fiのパスワード
char *password = "";
// MQTTの接続先のIP
const char *endpoint = "";
// MQTTのポート
const int port = 1883;
// デバイスID
char *deviceID = "M5Stack";  // デバイスIDは機器ごとにユニークにします
// メッセージを知らせるトピック
char *userName = "";              // MQTTブローカ認証ユーザ名
char *userPass = "";      // MQTTブローカ認証パスワード
char *pubTopic = "/pub/M5Stack";
// メッセージを待つトピック
char *subTopic = "/sub/M5Stack";

TTS tts;

AudioGeneratorMP3 *mp3;
AudioFileSourceICYStream *file;
AudioFileSourceBuffer *buff;
AudioOutputI2S *out;

////////////////////////////////////////////////////////////////////////////////

WiFiClient httpsClient;
PubSubClient mqttClient(httpsClient);


void setup() {
  Serial.begin(115200);
  M5.begin();

  // Start WiFi
  Serial.println("Connecting to ");
  Serial.print(ssid);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
  }

  // WiFi Connected
  Serial.println("\nWiFi Connected.");

  mqttClient.setServer(endpoint, port);
  mqttClient.setCallback(mqttCallback);

  Serial.println(tts.getSpeechUrl("こんにちは、世界!", "ja"));
  Serial.println(tts.getSpeechUrl("Hello, World!"));

  connectMQTT();

}

void loop() {
  mqttLoop();
  M5.update();
if (M5.Btn.isPressed()){
  speakText("こんにちは、私です");
}


  delay(100);
}

void speakText(String text){

  Serial.println(text);

  String http = "http" + tts.getSpeechUrl(text, "ja").substring(5);
  Serial.println(http);

  audioLogger = &Serial;
  file = new AudioFileSourceICYStream( (const char *)http.c_str() );
  file->RegisterMetadataCB(MDCallback, (void*)"ICY");
  buff = new AudioFileSourceBuffer(file, 10240);
  buff->RegisterStatusCB(StatusCallback, (void*)"buffer");
  out = new AudioOutputI2S();
  out->SetPinout(CONFIG_I2S_BCK_PIN, CONFIG_I2S_LRCK_PIN, CONFIG_I2S_DATA_PIN);
  out->SetChannels(1);
  out->SetGain(0.4);
  mp3 = new AudioGeneratorMP3();
  mp3->RegisterStatusCB(StatusCallback, (void*)"mp3");
  mp3->begin(buff, out);

  while(mp3->isRunning()) {
    Serial.println("playing");

    if (!mp3->loop()) {
      mp3->stop();
      break;
    }
  }
}

void MDCallback(void *cbData, const char *type, bool isUnicode, const char *string)
{
  const char *ptr = reinterpret_cast<const char *>(cbData);
  (void) isUnicode; // Punt this ball for now
  // Note that the type and string may be in PROGMEM, so copy them to RAM for printf
  char s1[32], s2[64];
  strncpy_P(s1, type, sizeof(s1));
  s1[sizeof(s1)-1]=0;
  strncpy_P(s2, string, sizeof(s2));
  s2[sizeof(s2)-1]=0;
  Serial.printf("METADATA(%s) '%s' = '%s'\n", ptr, s1, s2);
  Serial.flush();
}

// Called when there's a warning or error (like a buffer underflow or decode hiccup)
void StatusCallback(void *cbData, int code, const char *string)
{
  const char *ptr = reinterpret_cast<const char *>(cbData);
  // Note that the string may be in PROGMEM, so copy it to RAM for printf
  char s1[64];
  strncpy_P(s1, string, sizeof(s1));
  s1[sizeof(s1)-1]=0;
  Serial.printf("STATUS(%s) '%d' = '%s'\n", ptr, code, s1);
  Serial.flush();
}


void mqttCallback (char* topic, byte* payload, unsigned int length) {

    String str = "";
    Serial.print("Received. topic=");
    Serial.println(topic);
    for (int i = 0; i < length; i++) {
        Serial.print((char)payload[i]);
        str += (char)payload[i];
    }
    String text = str;

    speakText(text);

}

void connectMQTT() {
    while (!mqttClient.connected()) {
        if (mqttClient.connect(deviceID,userName,userPass)) {
            Serial.println("Connected.");
            int qos = 0;
            mqttClient.subscribe(subTopic, qos);
            Serial.println("Subscribed.");
        } else {
            Serial.print("Failed. Error state=");
            Serial.println(mqttClient.state());
            errorReport();
            // Wait 5 seconds before retrying
            delay(5000);
        }
    }
}
void mqttLoop() {
    if (!mqttClient.connected()) {
        connectMQTT();
    }
    mqttClient.loop();
}

void errorReport(){
  Serial.print("Failed. Error state = ");

  switch (mqttClient.state()) {
    case MQTT_CONNECT_UNAUTHORIZED:
      Serial.println("MQTT_CONNECT_UNAUTHORIZED");
      break;
    case MQTT_CONNECT_BAD_CREDENTIALS:
      Serial.println("MQTT_CONNECT_BAD_CREDENTIALS");
      break;
    case MQTT_CONNECT_UNAVAILABLE:
      Serial.println("MQTT_CONNECT_UNAVAILABLE");
      break;
    case MQTT_CONNECT_BAD_CLIENT_ID:
      Serial.println("MQTT_CONNECT_BAD_CLIENT_ID");
      break;
    case MQTT_CONNECT_BAD_PROTOCOL:
      Serial.println("MQTT_CONNECT_BAD_PROTOCOL");
      break;
    case MQTT_CONNECTED:
      Serial.println("MQTT_CONNECTED");
      break;
    case MQTT_DISCONNECTED:
      Serial.println("MQTT_DISCONNECTED");
      break;
    case MQTT_CONNECT_FAILED:
      Serial.println("MQTT_CONNECT_FAILED");
      break;
    case MQTT_CONNECTION_LOST:
      Serial.println("MQTT_CONNECTION_LOST");
      break;
    case MQTT_CONNECTION_TIMEOUT:
      Serial.println("MQTT_CONNECTION_TIMEOUT");
      break;
  }

  delay(5000); // Wait 5 seconds before retrying
}

enebular

ツイッターノードをインストール

パレットから、node-red-node-twitterを追加し、下記のようにつなぎます。
スクリーンショット 2020-12-20 18.29.12.png

Twitter

TwitterのDeveloperコンソールから新しくアプリを作成。
developer.twitter.com/en/apps
スクリーンショット 2020-12-20 18.16.59.png

  • API key
  • API secret key
  • Access token
  • Access token secret を生成し、ノードに設定。 スクリーンショット 2020-12-20 18.08.46.png

ニュースのツイッターアカウントなど、早く情報を知りたいアカウントを設定すると便利そうです。

9
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2