diff --git a/sonoff/xdrv_91_mp3.ino b/sonoff/xdrv_91_mp3.ino new file mode 100644 index 000000000..82c778127 --- /dev/null +++ b/sonoff/xdrv_91_mp3.ino @@ -0,0 +1,117 @@ +/* + xdrv_91_mp3.ino - MP3 Player support for Sonoff-Tasmota + Player type: RB-DFR-562, DFPlayer Mini MP3 Player + Copyright (C) 2018 Theo Arends + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifdef USE_MP3_PLAYER + +#include + +TasmotaSerial *MP3Player; + +#define D_CMND_MP3 "MP3" +const char S_JSON_MP3_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_MP3 "%s\":%d}"; +const char S_JSON_MP3_COMMAND[] PROGMEM = "{\"" D_CMND_MP3 "%s\"}"; + +enum MP3_Commands { CMND_MP3_PLAY, CMND_MP3_STOP, CMND_MP3_VOLUME}; +const char kMP3_Commands[] PROGMEM = "Play" "|" "Stop" "|" "Volume"; + +#define MP3_CMD_PLAY 3 +#define MP3_CMD_VOLUME 6 +#define MP3_CMD_STOP 0x0e + +uint16_t MP3_Checksum(uint8_t *array) +{ + uint16_t checksum = 0; + for (uint8_t i = 0; i < 6; i++) { + checksum += array[i]; + } + checksum = checksum^0xffff; + return checksum+1; +} + +// init player define serial tx port +void InitMP3Player() { + MP3Player = new TasmotaSerial(-1, pin[GPIO_MP3PLAYER]); + + if (MP3Player->begin(9600)) { + //serial_bridge_active = 1; + MP3Player->flush(); + } +} + +void MP3_CMD(uint8_t mp3cmd,uint16_t val) { + uint8_t cmd[10] = {0x7e,0xff,6,0,0,0,0,0,0,0xef}; + cmd[3] = mp3cmd; + cmd[5] = val>>8; + cmd[6] = val; + uint16_t chks = MP3_Checksum(&cmd[1]); // calculate out + cmd[7] = chks>>8; + cmd[8] = chks; + MP3Player->write(cmd, sizeof(cmd)); +} + +boolean MP3PlayerCmd() { + char command[CMDSZ]; + boolean serviced = true; + uint8_t disp_len = strlen(D_CMND_MP3); + + if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_MP3), disp_len)) { // Prefix + int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + disp_len, kMP3_Commands); + + if (CMND_MP3_PLAY == command_code) { + if (XdrvMailbox.data_len > 0) { // play + MP3_CMD(MP3_CMD_PLAY, XdrvMailbox.payload); + } + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_MP3_COMMAND_NVALUE, command, XdrvMailbox.payload); + } + else if (CMND_MP3_VOLUME == command_code) { + if (XdrvMailbox.data_len > 0) { // set volume + MP3_CMD(MP3_CMD_VOLUME, XdrvMailbox.payload * 30 / 100); + } + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_MP3_COMMAND_NVALUE, command, XdrvMailbox.payload); + } + else if (CMND_MP3_STOP == command_code) { // stop + MP3_CMD(MP3_CMD_STOP, 0); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_MP3_COMMAND, command, XdrvMailbox.payload); + } else { + serviced = false; // Unknown command + } + } + return serviced; +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +#define XDRV_91 + +boolean Xdrv91(byte function) +{ + boolean result = false; + + switch (function) { + case FUNC_PRE_INIT: + InitMP3Player(); + break; + case FUNC_COMMAND: + result = MP3PlayerCmd(); + break; + } + return result; +} + +#endif // USE_MP3_PLAYER