
Zasilanie 3,3V – 5V
Obsługa modułu
Uczenie dodatkowej frazy wybudzającej
Aby nauczyć moduł nowej frazy wybudzającej (zawsze aktywne pozostaje „Hello Robot!„) należy po wywołaniu standardowym wygłosić frazę: Learning wake word„. Następnie podać nowe sformułowanie wybudzające. Ja podałem Hello Jane. Trzeba to zrobić trzykrotnie słuchając poleceń.
Kod dla Arduino z biblioteką DFRobot_DF2301QG v1.0
Według AI lepszym wyborem w przypadku DF2301QG jest język Arduino. Mamy stabilną bibliotekę dla połączenia I2C. Należy pamiętać, by ustawić Communication Mode Select w module w tej właśnie pozycji.
Biblioteka Arduino: https://github.com/DFRobot/DFRobot_DF2301Q
Poniżej kod na mikrokontroler ESP32 połączony przez I2C z modułem DF2301QG v1.0. Łączy się z serwerem MQTT i wysyła ID usłyszanych komendy na mqtt_topic.
// Hello Robot!
#include <WiFi.h>
#include <PubSubClient.h>
#include <DFRobot_DF2301Q.h>
#include <Wire.h>
#include "config.h"
// ================= USTAWIENIA WI-FI =================
const char* ssid = WIFI_SSID;
const char* password = WIFI_PASSWORD;
// ================= USTAWIENIA MQTT =================
const char* mqtt_server = MQTT_SERVER;
const int mqtt_port = MQTT_PORT;
const char* mqtt_topic = MQTT_TOPIC_VOICE;
const char* mqtt_client_id = MQTT_CLIENT;
// Piny I2C dla ESP32
#define I2C_SDA 21
#define I2C_SCL 22
// Inicjalizacja obiektów
WiFiClient espClient;
PubSubClient client(espClient);
DFRobot_DF2301Q_I2C asr;
// Zmienne do opóźnień
unsigned long lastReconnectAttempt = 0;
unsigned long lastVoiceCheck = 0;
void printProgramInfo() {
while (!Serial) { ; }
Serial.println();
Serial.println("-----------------------------");
Serial.println("--- Informacje o programie ---");
Serial.print("Nazwa programu: ");
Serial.println(__FILE__);
Serial.print("Data kompilacji: ");
Serial.print(__DATE__);
Serial.print(" ");
Serial.println(__TIME__);
Serial.println("-----------------------------");
}
// Funkcja łącząca z Wi-Fi
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Łączenie z siecią Wi-Fi: ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.setAutoReconnect(true);
WiFi.persistent(true);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nPołączono z Wi-Fi!");
Serial.print("Adres IP: ");
Serial.println(WiFi.localIP());
}
// Funkcja MQTT
boolean reconnectMQTT() {
Serial.print("Próba połączenia z MQTT...");
if (client.connect(mqtt_client_id)) {
Serial.println(" Połączono z Mosquitto!");
return true;
} else {
Serial.print(" Błąd, rc=");
Serial.print(client.state());
Serial.println(" - kolejna próba za 5 sekund.");
return false;
}
}
void setup() {
Serial.begin(115200);
printProgramInfo();
Wire.begin(I2C_SDA, I2C_SCL);
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
Serial.println("Inicjalizacja modułu DF2301Q...");
if (!(asr.begin())) {
Serial.println("Błąd komunikacji z modułem DF2301Q. Sprawdź połączenia I2C!");
while (1) { yield(); }
}
Serial.println("Moduł mowy zainicjowany pomyślnie.");
asr.setVolume(7);
asr.setMuteMode(0);
asr.setWakeTime(20);
}
void loop() {
// 1. Sprawdzanie Wi-Fi
if (WiFi.status() == WL_CONNECTED) {
// 2. Obsługa MQTT (tylko jeśli jest Wi-Fi)
if (!client.connected()) {
unsigned long now = millis();
if (now - lastReconnectAttempt > 5000) {
lastReconnectAttempt = now;
reconnectMQTT();
}
} else {
client.loop(); // Podtrzymanie komunikacji z Mosquitto
}
}
// 3. Odczyt komendy z czujnika mowy (ZAWSZE, NAWET BEZ MQTT!)
// Zwiększony interwał z 50ms na 250ms dla stabilności szyny I2C
unsigned long currentMillis = millis();
if (currentMillis - lastVoiceCheck >= 250) {
lastVoiceCheck = currentMillis;
uint8_t CMDID = asr.getCMDID();
// Dodano zabezpieczenie przed kodem błędu I2C (255)
if (CMDID != 0 && CMDID != 98 && CMDID != 255) {
Serial.print("✅ Rozpoznano komendę o ID: ");
Serial.println(CMDID);
// 4. Publikacja MQTT - wysyłamy tylko wtedy, gdy serwer faktycznie nas słucha
if (client.connected()) {
char payload[10];
itoa(CMDID, payload, 10);
if (client.publish(mqtt_topic, payload, false)) {
Serial.println(" -> Wysłano do MQTT pomyślnie.");
} else {
Serial.println(" -> Błąd wysyłania do MQTT.");
}
} else {
Serial.println(" -> ⚠️ Brak połączenia z MQTT! Komenda usłyszana, ale nie wysłana.");
}
}
}
}
Tabela komend z ID (PDF)
…
Flow dla Node-RED włączający i wyłączający światło (komenda 103, 104) podpięte do odbiornika na „topic”: „d1mini/urzadzenie1/set” ON, OFF
[
{
"id": "750214f6e6c63297",
"type": "tab",
"label": "Flow 3",
"disabled": false,
"info": "",
"env": []
},
{
"id": "s1",
"type": "switch",
"z": "750214f6e6c63297",
"name": "Wybór ID",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "103",
"vt": "num"
},
{
"t": "eq",
"v": "104",
"vt": "num"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 360,
"y": 140,
"wires": [
[
"c1"
],
[
"c2"
]
]
},
{
"id": "c1",
"type": "change",
"z": "750214f6e6c63297",
"name": "Zamień na ON",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "OFF",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 560,
"y": 120,
"wires": [
[
"m1"
]
]
},
{
"id": "c2",
"type": "change",
"z": "750214f6e6c63297",
"name": "Zamień na OFF",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "ON",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 560,
"y": 160,
"wires": [
[
"m1"
]
]
},
{
"id": "m1",
"type": "mqtt out",
"z": "750214f6e6c63297",
"name": "",
"topic": "d1mini/urzadzenie1/set",
"qos": "1",
"retain": "",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "be57f5ae9b4c6eb4",
"x": 810,
"y": 140,
"wires": []
},
{
"id": "31c29f1ad59174b1",
"type": "mqtt in",
"z": "750214f6e6c63297",
"name": "Głos ESP32",
"topic": "home/voice1/commands",
"qos": "1",
"datatype": "auto-detect",
"broker": "be57f5ae9b4c6eb4",
"nl": false,
"rap": false,
"inputs": 0,
"x": 190,
"y": 140,
"wires": [
[
"s1",
"ea3cb018ea7ed788"
]
]
},
{
"id": "ea3cb018ea7ed788",
"type": "debug",
"z": "750214f6e6c63297",
"name": "debug 2",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 320,
"y": 240,
"wires": []
},
{
"id": "be57f5ae9b4c6eb4",
"type": "mqtt-broker",
"name": "",
"broker": "localhost",
"port": 1883,
"clientid": "",
"autoConnect": true,
"usetls": false,
"protocolVersion": 4,
"keepalive": 60,
"cleansession": true,
"autoUnsubscribe": true,
"birthTopic": "",
"birthQos": "0",
"birthRetain": "false",
"birthPayload": "",
"birthMsg": {},
"closeTopic": "",
"closeQos": "0",
"closeRetain": "false",
"closePayload": "",
"closeMsg": {},
"willTopic": "",
"willQos": "0",
"willRetain": "false",
"willPayload": "",
"willMsg": {},
"userProps": "",
"sessionExpiry": ""
}
]
MICROPYTHON
Biblioteka MicroPython
Biblioteka lekko zmodyfikowana. W oryginalnej był błąd w metodzie get_cmdid(). Poprawiony przez Chat GPT.
Uwaga! Kody nie działają dla ESP8266. Prawdopodobnie problem tkwi w bibliotece I2C. Może trzeba użyć softI2C? Sprawdzę.
Wszystko dobrze działa na ESP32.
from micropython import const
from machine import I2C, Pin
from utime import sleep
DF2301Q_I2C_ADDR = const(0x64)
class DFRobot_DF2301Q_I2C:
"""
MicroPython class for communication with the DF2301Q from DFRobot via I2C
"""
DF2301Q_I2C_REG_CMDID = const(0x02)
DF2301Q_I2C_REG_PLAY_CMDID = const(0x03)
DF2301Q_I2C_REG_SET_MUTE = const(0x04)
DF2301Q_I2C_REG_SET_VOLUME = const(0x05)
DF2301Q_I2C_REG_WAKE_TIME = const(0x06)
DF2301Q_I2C_8BIT_RANGE = const(0xFF)
DF2301Q_I2C_PLAY_CMDID_DURATION = const(1)
def __init__(self, sda, scl, i2c_addr=DF2301Q_I2C_ADDR, i2c_bus=0):
"""
Initialize the DF2301Q I2C communication
:param sda: I2C SDA pin
:param scl: I2C SCL pin
:param i2c_addr: I2C address
:param i2c_bus: I2C bus number
"""
self._addr = i2c_addr
try:
self._i2c = I2C(i2c_bus, sda=Pin(sda), scl=Pin(scl))
except Exception as err:
print(f'Could not initialize i2c! bus: {i2c_bus}, sda: {sda}, scl: {scl}, error: {err}')
def _write_reg(self, reg, data) -> None:
"""
Writes data to the I2C register
:param reg: register address
:param data: data to write
:return: None
"""
if isinstance(data, int):
data = [data]
try:
self._i2c.writeto_mem(self._addr, reg, bytearray(data))
except Exception as err:
print(f'Write issue: {err}')
def _read_reg(self, reg, length) -> bytes:
"""
Reads data from the I2C register
:param reg: register address
:param length: number of bytes to read
:return: bytes
"""
try:
result = self._i2c.readfrom_mem(self._addr, reg, length)
except Exception as err:
print(f'Read issue: {err}')
result = bytearray(length)
return result
def get_cmdid(self) -> int:
"""
Returns the current command id
:return: int
"""
data = self._read_reg(self.DF2301Q_I2C_REG_CMDID, 1)
return int(data[0])
def get_wake_time(self) -> int:
"""
Returns the current wake-up duration
:return: int
"""
data = self._read_reg(self.DF2301Q_I2C_REG_WAKE_TIME, 1)
return int(data[0])
def play_by_cmdid(self, cmdid: int) -> None:
"""
Play the current command words by command id
:param cmdid: command words as integer
:return: None
"""
self._write_reg(self.DF2301Q_I2C_REG_PLAY_CMDID, int(cmdid))
sleep(self.DF2301Q_I2C_PLAY_CMDID_DURATION)
def set_wake_time(self, wake_time: int) -> None:
"""
Set the wake-up duration of the device
:param wake_time: integer between 0 and 255
:return: None
"""
wake_up_time = int(wake_time) & self.DF2301Q_I2C_8BIT_RANGE
self._write_reg(self.DF2301Q_I2C_REG_WAKE_TIME, wake_up_time)
def set_volume(self, vol: int) -> None:
"""
Set the volume of the device
:param vol: integer between 1 and 7
:return: None
"""
self._write_reg(self.DF2301Q_I2C_REG_SET_VOLUME, int(vol))
def set_mute_mode(self, mode) -> None:
"""
Set the mute mode of the device
:param mode: integer 0 for off, 1 for on
:return: None
"""
self._write_reg(self.DF2301Q_I2C_REG_SET_MUTE, int(bool(mode)))
Kod programu wyświetlającego na konsoli numery komend głosowych
from DFRobot_DF2301Q_I2C import DFRobot_DF2301Q_I2C
from micropython import const
from utime import sleep
SDA_PIN = const(21)
SCL_PIN = const(22)
SLEEP_SECONDS = const(3)
def setup(sensor) -> None:
"""
Set up the DFRobot DF2301Q sensor
:param sensor: instance of DFRobot_DF2301Q_I2C
:return: None
"""
sensor.set_volume(5)
sensor.set_mute_mode(0)
sensor.set_wake_time(20)
def get_cmd_id(sensor) -> int:
"""
Get the command id from the DF2301Q sensor
:param sensor: instance of DFRobot_DF2301Q_I2C
:return: int
"""
command_id = sensor.get_cmdid()
return command_id if command_id != 0 else None
if __name__ == "__main__":
try:
voice_sensor = DFRobot_DF2301Q_I2C(sda=SDA_PIN, scl=SCL_PIN)
setup(sensor=voice_sensor)
print('Speak your commands:')
while True:
cmd_id = get_cmd_id(sensor=voice_sensor)
if cmd_id is not None:
print(f'COMMAND ID: {cmd_id}')
sleep(SLEEP_SECONDS)
except Exception as e:
print(f'Initialization error: {e}')
LINKI
- Oficjalna biblioteka Arduino:
- Dokumentacja:
- Biblioteka MicroPython (uwaga, błąd!):
- NerdCave, MicroPython