Split code between ulanzi environment and awtrix_upgrade

Added BME280 sensor support for awtrix_upgrade.

Removed battery readings for awtrix_upgrade

Added DFMiniMp3 lib for replacing the Ulanzi buzzer in the future
This commit is contained in:
Elfish
2023-03-31 15:12:13 +02:00
parent 5fb65e96c1
commit 055d54d099
22 changed files with 1331 additions and 5 deletions

View File

@@ -0,0 +1,17 @@
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

View File

@@ -0,0 +1,2 @@
github: [makuna]
custom: ["https://paypal.me/MakunaGithub"]

View File

@@ -0,0 +1,79 @@
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# =========================
# Operating System Files
# =========================
# OSX
# =========================
.DS_Store
.AppleDouble
.LSOverride
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# Windows
# =========================
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk

View File

@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View File

@@ -0,0 +1,25 @@
# DFPlayer Mini mp3
[![Join the chat at https://gitter.im/DFMiniMp3/Lobby](https://badges.gitter.im/DFMiniMp3/Lobby.svg)](https://gitter.im/DFMiniMp3/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Donate](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6AA97KE54UJR4)
Library for the DFPlayer Mini Mp3 module
This library allows your Arduino project to control the DFPlayer Mini MP3 module. It supports both hardware serial and software serial. It was designed to fit in the smallest Arduino hardware by consuming less code and memory space than other libraries.
Please read the product link before connecting your module, it will save you alot of time and effort.
[DFRobot's DFPlayer Mini Mp3](http://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299)
## Documentation
[See Wiki](https://github.com/Makuna/DFMiniMp3/wiki)
## Installing This Library (prefered, you just want to use it)
Open the Library Manager and search for "DFPlayer Mini Mp3 by Makuna" and install.
## Installing This Library From GitHub (advanced, you want to contribute)
Create a directory in your Arduino\Library folder named "DfMiniMp3"
Clone (Git) this project into that folder.
It should now show up in the import list when you restart Arduino IDE.

View File

@@ -0,0 +1,105 @@
// this example will play a track and then every 60 seconds
// it will play an advertisement
//
// it expects the sd card to contain the following mp3 files
// but doesn't care whats in them
//
// sd:/01/001.mp3 - the song to play, the longer the better
// sd:/advert/0001.mp3 - the advertisement to interrupt the song, keep it short
#include <SoftwareSerial.h>
#include <DFMiniMp3.h>
// implement a notification class,
// its member methods will get called
//
class Mp3Notify
{
public:
static void PrintlnSourceAction(DfMp3_PlaySources source, const char* action)
{
if (source & DfMp3_PlaySources_Sd)
{
Serial.print("SD Card, ");
}
if (source & DfMp3_PlaySources_Usb)
{
Serial.print("USB Disk, ");
}
if (source & DfMp3_PlaySources_Flash)
{
Serial.print("Flash, ");
}
Serial.println(action);
}
static void OnError(uint16_t errorCode)
{
// see DfMp3_Error for code meaning
Serial.println();
Serial.print("Com Error ");
Serial.println(errorCode);
}
static void OnPlayFinished(DfMp3_PlaySources source, uint16_t track)
{
Serial.print("Play finished for #");
Serial.println(track);
}
static void OnPlaySourceOnline(DfMp3_PlaySources source)
{
PrintlnSourceAction(source, "online");
}
static void OnPlaySourceInserted(DfMp3_PlaySources source)
{
PrintlnSourceAction(source, "inserted");
}
static void OnPlaySourceRemoved(DfMp3_PlaySources source)
{
PrintlnSourceAction(source, "removed");
}
};
// instance a DFMiniMp3 object,
// defined with the above notification class and the hardware serial class
//
DFMiniMp3<HardwareSerial, Mp3Notify> mp3(Serial1);
// Some arduino boards only have one hardware serial port, so a software serial port is needed instead.
// comment out the above definition and uncomment these lines
//SoftwareSerial secondarySerial(10, 11); // RX, TX
//DFMiniMp3<SoftwareSerial, Mp3Notify> mp3(secondarySerial);
uint32_t lastAdvert; // track time for last advertisement
void setup()
{
Serial.begin(115200);
Serial.println("initializing...");
mp3.begin();
uint16_t volume = mp3.getVolume();
Serial.print("volume was ");
Serial.println(volume);
mp3.setVolume(24);
volume = mp3.getVolume();
Serial.print(" and changed to ");
Serial.println(volume);
Serial.println("track 1 from folder 1");
mp3.playFolderTrack(1, 1); // sd:/01/001.mp3
lastAdvert = millis();
}
void loop()
{
uint32_t now = millis();
if ((now - lastAdvert) > 60000)
{
// interrupt the song and play the advertisement, it will
// return to the song when its done playing automatically
mp3.playAdvertisement(1); // sd:/advert/0001.mp3
lastAdvert = now;
}
mp3.loop();
}

View File

@@ -0,0 +1,121 @@
// this example will play a track and then
// every five seconds play another track
//
// it expects the sd card to contain these three mp3 files
// but doesn't care whats in them
//
// sd:/mp3/0001.mp3
// sd:/mp3/0002.mp3
// sd:/mp3/0003.mp3
#include <SoftwareSerial.h>
#include <DFMiniMp3.h>
// implement a notification class,
// its member methods will get called
//
class Mp3Notify
{
public:
static void PrintlnSourceAction(DfMp3_PlaySources source, const char* action)
{
if (source & DfMp3_PlaySources_Sd)
{
Serial.print("SD Card, ");
}
if (source & DfMp3_PlaySources_Usb)
{
Serial.print("USB Disk, ");
}
if (source & DfMp3_PlaySources_Flash)
{
Serial.print("Flash, ");
}
Serial.println(action);
}
static void OnError(uint16_t errorCode)
{
// see DfMp3_Error for code meaning
Serial.println();
Serial.print("Com Error ");
Serial.println(errorCode);
}
static void OnPlayFinished(DfMp3_PlaySources source, uint16_t track)
{
Serial.print("Play finished for #");
Serial.println(track);
}
static void OnPlaySourceOnline(DfMp3_PlaySources source)
{
PrintlnSourceAction(source, "online");
}
static void OnPlaySourceInserted(DfMp3_PlaySources source)
{
PrintlnSourceAction(source, "inserted");
}
static void OnPlaySourceRemoved(DfMp3_PlaySources source)
{
PrintlnSourceAction(source, "removed");
}
};
// instance a DFMiniMp3 object,
// defined with the above notification class and the hardware serial class
//
DFMiniMp3<HardwareSerial, Mp3Notify> mp3(Serial1);
// Some arduino boards only have one hardware serial port, so a software serial port is needed instead.
// comment out the above definition and uncomment these lines
//SoftwareSerial secondarySerial(10, 11); // RX, TX
//DFMiniMp3<SoftwareSerial, Mp3Notify> mp3(secondarySerial);
void setup()
{
Serial.begin(115200);
Serial.println("initializing...");
mp3.begin();
uint16_t volume = mp3.getVolume();
Serial.print("volume ");
Serial.println(volume);
mp3.setVolume(24);
uint16_t count = mp3.getTotalTrackCount(DfMp3_PlaySource_Sd);
Serial.print("files ");
Serial.println(count);
Serial.println("starting...");
}
void waitMilliseconds(uint16_t msWait)
{
uint32_t start = millis();
while ((millis() - start) < msWait)
{
// calling mp3.loop() periodically allows for notifications
// to be handled without interrupts
mp3.loop();
delay(1);
}
}
void loop()
{
Serial.println("track 1");
mp3.playMp3FolderTrack(1); // sd:/mp3/0001.mp3
waitMilliseconds(5000);
Serial.println("track 2");
mp3.playMp3FolderTrack(2); // sd:/mp3/0002.mp3
waitMilliseconds(5000);
Serial.println("track 3");
mp3.playMp3FolderTrack(3); // sd:/mp3/0002.mp3
waitMilliseconds(5000);
}

View File

@@ -0,0 +1,100 @@
// this example will play a random track from all on the sd
//
// it expects the sd card to contain some mp3 files
#include <SoftwareSerial.h>
#include <DFMiniMp3.h>
// implement a notification class,
// its member methods will get called
//
class Mp3Notify
{
public:
static void PrintlnSourceAction(DfMp3_PlaySources source, const char* action)
{
if (source & DfMp3_PlaySources_Sd)
{
Serial.print("SD Card, ");
}
if (source & DfMp3_PlaySources_Usb)
{
Serial.print("USB Disk, ");
}
if (source & DfMp3_PlaySources_Flash)
{
Serial.print("Flash, ");
}
Serial.println(action);
}
static void OnError(uint16_t errorCode)
{
// see DfMp3_Error for code meaning
Serial.println();
Serial.print("Com Error ");
Serial.println(errorCode);
}
static void OnPlayFinished(DfMp3_PlaySources source, uint16_t track)
{
Serial.print("Play finished for #");
Serial.println(track);
}
static void OnPlaySourceOnline(DfMp3_PlaySources source)
{
PrintlnSourceAction(source, "online");
}
static void OnPlaySourceInserted(DfMp3_PlaySources source)
{
PrintlnSourceAction(source, "inserted");
}
static void OnPlaySourceRemoved(DfMp3_PlaySources source)
{
PrintlnSourceAction(source, "removed");
}
};
// instance a DFMiniMp3 object,
// defined with the above notification class and the hardware serial class
//
DFMiniMp3<HardwareSerial, Mp3Notify> mp3(Serial1);
// Some arduino boards only have one hardware serial port, so a software serial port is needed instead.
// comment out the above definition and uncomment these lines
//SoftwareSerial secondarySerial(10, 11); // RX, TX
//DFMiniMp3<SoftwareSerial, Mp3Notify> mp3(secondarySerial);
void setup()
{
Serial.begin(115200);
Serial.println("initializing...");
mp3.begin();
mp3.reset();
// show some properties and set the volume
uint16_t volume = mp3.getVolume();
Serial.print("volume ");
Serial.println(volume);
mp3.setVolume(24);
uint16_t count = mp3.getTotalTrackCount(DfMp3_PlaySource_Sd);
Serial.print("files ");
Serial.println(count);
uint16_t mode = mp3.getPlaybackMode();
Serial.print("playback mode ");
Serial.println(mode);
Serial.println("starting...");
mp3.playRandomTrackFromAll(); // random of all folders on sd
}
void loop()
{
// calling mp3.loop() periodically allows for notifications
// to be handled without interrupts
mp3.loop();
}

View File

@@ -0,0 +1,79 @@
#######################################
# Syntax Coloring Map for DFMiniMp3
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
DFMiniMp3 KEYWORD1
DfMp3_PlaybackMode KEYWORD1
DfMp3_Eq KEYWORD1
DfMp3_PlaySource KEYWORD1
DfMp3_PlaySources KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
loop KEYWORD2
getPlaySources KEYWORD2
playGlobalTrack KEYWORD2
playMp3FolderTrack KEYWORD2
playFolderTrack KEYWORD2
playFolderTrack16 KEYWORD2
playRandomTrackFromAll KEYWORD2
nextTrack KEYWORD2
prevTrack KEYWORD2
getCurrentTrack KEYWORD2
setVolume KEYWORD2
getVolume KEYWORD2
increaseVolume KEYWORD2
decreaseVolume KEYWORD2
loopGlobalTrack KEYWORD2
loopFolder KEYWORD2
getPlaybackMode KEYWORD2
setRepeatPlayAllInRoot KEYWORD2
setRepeatPlayCurrentTrack KEYWORD2
setEq KEYWORD2
getEq KEYWORD2
setPlaybackSource KEYWORD2
sleep KEYWORD2
reset KEYWORD2
start KEYWORD2
pause KEYWORD2
stop KEYWORD2
getStatus KEYWORD2
getFolderTrackCount KEYWORD2
getTotalTrackCount KEYWORD2
getTotalFolderCount KEYWORD2
playAdvertisement KEYWORD2
stopAdvertisement KEYWORD2
enableDac KEYWORD2
disableDac KEYWORD2
isOnline KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
DfMp3_PlaybackMode_Repeat LITERAL1
DfMp3_PlaybackMode_FolderRepeat LITERAL1
DfMp3_PlaybackMode_SingleRepeat LITERAL1
DfMp3_PlaybackMode_Random LITERAL1
DfMp3_Eq_Normal LITERAL1
DfMp3_Eq_Pop LITERAL1
DfMp3_Eq_Rock LITERAL1
DfMp3_Eq_Jazz LITERAL1
DfMp3_Eq_Classic LITERAL1
DfMp3_Eq_Bass LITERAL1
DfMp3_PlaySource_Usb LITERAL1
DfMp3_PlaySource_Sd LITERAL1
DfMp3_PlaySource_Aux LITERAL1
DfMp3_PlaySource_Sleep LITERAL1
DfMp3_PlaySource_Flash LITERAL1
DfMp3_PlaySources_Usb LITERAL1
DfMp3_PlaySources_Sd LITERAL1
DfMp3_PlaySources_Pc LITERAL1
DfMp3_PlaySources_Flash LITERAL1

View File

@@ -0,0 +1,9 @@
name=DFPlayer Mini Mp3 by Makuna
version=1.0.7
author=Michael C. Miller (makuna@live.com)
maintainer=Michael C. Miller (makuna@live.com)
sentence=Library for the DFPlayer Mini Mp3 module
paragraph=This library allows your Arduino project to control the DFPlayer Mini MP3 module. It supports both hardware serial and software serial. It was designed to fit in the smallest Arduino hardware by consuming less code and memory space than other libraries.
category=Device Control
url=https://github.com/Makuna/DFMiniMp3/wiki
architectures=*

View File

@@ -0,0 +1,559 @@
/*-------------------------------------------------------------------------
DFMiniMp3 library
Written by Michael C. Miller.
I invest time and resources providing this open source code,
please support me by dontating (see https://github.com/Makuna/DFMiniMp3)
-------------------------------------------------------------------------
This file is part of the Makuna/DFMiniMp3 library.
DFMiniMp3 is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
DFMiniMp3 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with DFMiniMp3. If not, see
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/
#pragma once
enum DfMp3_Error
{
// from device
DfMp3_Error_Busy = 1,
DfMp3_Error_Sleeping,
DfMp3_Error_SerialWrongStack,
DfMp3_Error_CheckSumNotMatch,
DfMp3_Error_FileIndexOut,
DfMp3_Error_FileMismatch,
DfMp3_Error_Advertise,
// from library
DfMp3_Error_RxTimeout = 0x81,
DfMp3_Error_PacketSize,
DfMp3_Error_PacketHeader,
DfMp3_Error_PacketChecksum,
DfMp3_Error_General = 0xff
};
enum DfMp3_PlaybackMode
{
DfMp3_PlaybackMode_Repeat,
DfMp3_PlaybackMode_FolderRepeat,
DfMp3_PlaybackMode_SingleRepeat,
DfMp3_PlaybackMode_Random
};
enum DfMp3_Eq
{
DfMp3_Eq_Normal,
DfMp3_Eq_Pop,
DfMp3_Eq_Rock,
DfMp3_Eq_Jazz,
DfMp3_Eq_Classic,
DfMp3_Eq_Bass
};
enum DfMp3_PlaySource // value - only one can be set
{
DfMp3_PlaySource_Usb = 1,
DfMp3_PlaySource_Sd,
DfMp3_PlaySource_Aux,
DfMp3_PlaySource_Sleep,
DfMp3_PlaySource_Flash
};
enum DfMp3_PlaySources // bitfield - more than one can be set
{
DfMp3_PlaySources_Usb = 0x01,
DfMp3_PlaySources_Sd = 0x02,
DfMp3_PlaySources_Pc = 0x04,
DfMp3_PlaySources_Flash = 0x08,
};
template <class T_SERIAL_METHOD, class T_NOTIFICATION_METHOD>
class DFMiniMp3
{
public:
DFMiniMp3(T_SERIAL_METHOD &serial) : _serial(serial),
_lastSendSpace(c_msSendSpace),
_isOnline(false)
{
}
void begin(unsigned long baud = 9600)
{
_serial.begin(baud);
_serial.setTimeout(10000);
_lastSend = millis();
}
void loop()
{
while (_serial.available() >= DfMp3_Packet_SIZE)
{
listenForReply(0x00);
}
}
// Does not work with all models.
// YX5200-24SS - sends reply
// MH2024K-24SS - sends NO reply --> results in error notification
DfMp3_PlaySources getPlaySources()
{
drainResponses();
sendPacket(0x3f);
return static_cast<DfMp3_PlaySources>(listenForReply(0x3f));
}
// the track as enumerated across all folders
void playGlobalTrack(uint16_t track = 0)
{
sendPacket(0x03, track);
}
// sd:/mp3/####track name
void playMp3FolderTrack(uint16_t track)
{
sendPacket(0x12, track);
}
// older devices: sd:/###/###track name
// newer devices: sd:/##/###track name
// folder and track numbers are zero padded
void playFolderTrack(uint8_t folder, uint8_t track)
{
uint16_t arg = (folder << 8) | track;
sendPacket(0x0f, arg);
}
// sd:/##/####track name
// track number must be four digits, zero padded
void playFolderTrack16(uint8_t folder, uint16_t track)
{
uint16_t arg = (((uint16_t)folder) << 12) | track;
sendPacket(0x14, arg);
}
void playRandomTrackFromAll()
{
sendPacket(0x18);
}
void nextTrack()
{
sendPacket(0x01);
}
void prevTrack()
{
sendPacket(0x02);
}
uint16_t getCurrentTrack(DfMp3_PlaySource source = DfMp3_PlaySource_Sd)
{
drainResponses();
uint8_t command;
switch (source)
{
case DfMp3_PlaySource_Usb:
command = 0x4b;
break;
case DfMp3_PlaySource_Sd:
command = 0x4c;
break;
case DfMp3_PlaySource_Flash:
command = 0x4d;
break;
default:
command = 0x4c;
break;
}
sendPacket(command);
return listenForReply(command);
}
// 0- 30
void setVolume(uint8_t volume)
{
sendPacket(0x06, volume);
}
uint8_t getVolume()
{
drainResponses();
sendPacket(0x43);
return static_cast<uint8_t>(listenForReply(0x43));
}
void increaseVolume()
{
sendPacket(0x04);
}
void decreaseVolume()
{
sendPacket(0x05);
}
// useless, removed
// 0-31
/*
void setVolume(bool mute, uint8_t volume)
{
uint16_t arg = (!mute << 8) | volume;
sendPacket(0x10, arg);
}
*/
void loopGlobalTrack(uint16_t globalTrack)
{
sendPacket(0x08, globalTrack);
}
// sd:/##/*
// 0-99
void loopFolder(uint8_t folder)
{
sendPacket(0x17, folder);
}
DfMp3_PlaybackMode getPlaybackMode()
{
drainResponses();
sendPacket(0x45);
return static_cast<DfMp3_PlaybackMode>(listenForReply(0x45));
}
void setRepeatPlayAllInRoot(bool repeat)
{
sendPacket(0x11, !!repeat);
}
void setRepeatPlayCurrentTrack(bool repeat)
{
sendPacket(0x19, !repeat);
}
void setEq(DfMp3_Eq eq)
{
sendPacket(0x07, eq);
}
DfMp3_Eq getEq()
{
drainResponses();
sendPacket(0x44);
return static_cast<DfMp3_Eq>(listenForReply(0x44));
}
void setPlaybackSource(DfMp3_PlaySource source)
{
sendPacket(0x09, source, 200);
}
void sleep()
{
sendPacket(0x0a);
}
void reset()
{
sendPacket(0x0c, 0, 600);
_isOnline = false;
}
void start()
{
sendPacket(0x0d);
}
void pause()
{
sendPacket(0x0e);
}
void stop()
{
sendPacket(0x16);
}
uint16_t getStatus()
{
drainResponses();
sendPacket(0x42);
return listenForReply(0x42);
}
uint16_t getFolderTrackCount(uint16_t folder)
{
drainResponses();
sendPacket(0x4e, folder);
return listenForReply(0x4e);
}
uint16_t getTotalTrackCount(DfMp3_PlaySource source)
{
drainResponses();
uint8_t command;
switch (source)
{
case DfMp3_PlaySource_Usb:
command = 0x47;
break;
case DfMp3_PlaySource_Sd:
command = 0x48;
break;
case DfMp3_PlaySource_Flash:
command = 0x49;
break;
default:
command = 0x48;
break;
}
sendPacket(command);
return listenForReply(command);
}
uint16_t getTotalFolderCount()
{
drainResponses();
sendPacket(0x4F);
return listenForReply(0x4F);
}
// sd:/advert/####track name
void playAdvertisement(uint16_t track)
{
sendPacket(0x13, track);
}
void stopAdvertisement()
{
sendPacket(0x15);
}
void enableDac()
{
sendPacket(0x1A, 0x00);
}
void disableDac()
{
sendPacket(0x1A, 0x01);
}
bool isOnline() const
{
return _isOnline;
}
private:
static const uint16_t c_msSendSpace = 50;
// 7E FF 06 0F 00 01 01 xx xx EF
// 0 -> 7E is start code
// 1 -> FF is version
// 2 -> 06 is length
// 3 -> 0F is command
// 4 -> 00 is no receive
// 5~6 -> 01 01 is argument
// 7~8 -> checksum = 0 - ( FF+06+0F+00+01+01 )
// 9 -> EF is end code
enum DfMp3_Packet
{
DfMp3_Packet_StartCode,
DfMp3_Packet_Version,
DfMp3_Packet_Length,
DfMp3_Packet_Command,
DfMp3_Packet_RequestAck,
DfMp3_Packet_HiByteArgument,
DfMp3_Packet_LowByteArgument,
DfMp3_Packet_HiByteCheckSum,
DfMp3_Packet_LowByteCheckSum,
DfMp3_Packet_EndCode,
DfMp3_Packet_SIZE
};
enum DfMp3_Packet_short
{
DfMp3_Packet_short_StartCode,
DfMp3_Packet_short_Version,
DfMp3_Packet_short_Length,
DfMp3_Packet_short_Command,
DfMp3_Packet_short_RequestAck,
DfMp3_Packet_short_HiByteArgument,
DfMp3_Packet_short_LowByteArgument,
// DfMp3_Packet_short_HiByteCheckSum,
// DfMp3_Packet_short_LowByteCheckSum,
DfMp3_Packet_short_EndCode,
DfMp3_Packet_short_SIZE
};
T_SERIAL_METHOD &_serial;
uint32_t _lastSend;
uint16_t _lastSendSpace;
bool _isOnline;
void drainResponses()
{
while (_serial.available() > 0)
{
listenForReply(0x00);
}
}
void sendPacket(uint8_t command, uint16_t arg = 0, uint16_t sendSpaceNeeded = c_msSendSpace)
{
uint8_t out[DfMp3_Packet_short_SIZE] = {0x7E,
0xFF,
06,
command,
00,
static_cast<uint8_t>(arg >> 8),
static_cast<uint8_t>(arg & 0x00ff),
// 00,
// 00,
0xEF};
// setChecksum(out);
// wait for spacing since last send
while (((millis() - _lastSend) < _lastSendSpace))
{
// check for event messages from the device while
// we wait
loop();
delay(1);
}
_lastSendSpace = sendSpaceNeeded;
_serial.write(out, DfMp3_Packet_short_SIZE);
_lastSend = millis();
}
bool readPacket(uint8_t *command, uint16_t *argument)
{
uint8_t in[DfMp3_Packet_SIZE] = {0};
uint8_t read;
// init our out args always
*command = 0;
*argument = 0;
// try to sync our reads to the packet start
do
{
// we use readBytes as it gives us the standard timeout
read = _serial.readBytes(&(in[DfMp3_Packet_StartCode]), 1);
if (read != 1)
{
// nothing read
*argument = DfMp3_Error_RxTimeout;
return false;
}
} while (in[DfMp3_Packet_StartCode] != 0x7e);
read += _serial.readBytes(in + 1, DfMp3_Packet_SIZE - 1);
if (read < DfMp3_Packet_SIZE)
{
// not enough bytes, corrupted packet
*argument = DfMp3_Error_PacketSize;
return false;
}
if (in[DfMp3_Packet_Version] != 0xFF ||
in[DfMp3_Packet_Length] != 0x06 ||
in[DfMp3_Packet_EndCode] != 0xef)
{
// invalid version or corrupted packet
*argument = DfMp3_Error_PacketHeader;
return false;
}
// if (!validateChecksum(in))
// {
// // checksum failed, corrupted packet
// *argument = DfMp3_Error_PacketChecksum;
// return false;
// }
*command = in[DfMp3_Packet_Command];
*argument = ((in[DfMp3_Packet_HiByteArgument] << 8) | in[DfMp3_Packet_LowByteArgument]);
return true;
}
uint16_t listenForReply(uint8_t command)
{
uint8_t replyCommand = 0;
uint16_t replyArg = 0;
do
{
if (readPacket(&replyCommand, &replyArg))
{
if (command != 0 && command == replyCommand)
{
return replyArg;
}
else
{
}
}
else
{
if (replyArg != 0)
{
if (_serial.available() == 0)
{
return 0;
}
}
}
} while (command != 0);
return 0;
}
// uint16_t calcChecksum(uint8_t *packet)
// {
// uint16_t sum = 0xFFFF;
// for (int i = DfMp3_Packet_Version; i < DfMp3_Packet_HiByteCheckSum; i++)
// {
// sum -= packet[i];
// }
// return sum + 1;
// }
// void setChecksum(uint8_t *out)
// {
// uint16_t sum = calcChecksum(out);
// out[DfMp3_Packet_HiByteCheckSum] = ((sum >> 8) & 0xFF);
// out[DfMp3_Packet_LowByteCheckSum] = (sum & 0xff);
// }
// bool validateChecksum(uint8_t *in)
// {
// uint16_t sum = calcChecksum(in);
// return (sum == static_cast<uint16_t>((in[DfMp3_Packet_HiByteCheckSum] << 8) | in[DfMp3_Packet_LowByteCheckSum]));
// }
};

View File

@@ -31,7 +31,7 @@ upload_speed = 921600
framework = arduino
build_flags = -DAWTRIX_UPGRADE -D MQTT_MAX_PACKET_SIZE=1024
lib_deps =
adafruit/Adafruit SHT31 Library@^2.2.0
adafruit/Adafruit BME280 Library@^2.2.2
bblanchon/ArduinoJson@^6.20.0
evert-arias/EasyButton@^2.0.1
fastled/FastLED@^3.5.0

View File

@@ -214,6 +214,7 @@ void HumApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, i
matrix->print("%");
}
#ifdef ULANZI
void BatApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{
if (notify.flag)
@@ -225,6 +226,7 @@ void BatApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, i
matrix->print(BATTERY_PERCENT); // Ausgabe des Ladezustands
matrix->print("%");
}
#endif
void MenuApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
{

View File

@@ -50,11 +50,13 @@ extern const char HAhumName[];
extern const char HAhumClass[];
extern const char HAhumUnit[];
#ifdef ULANZI
extern const char HAbatID[];
extern const char HAbatIcon[];
extern const char HAbatName[];
extern const char HAbatClass[];
extern const char HAbatUnit[];
#endif
extern const char HAluxID[];
extern const char HAluxIcon[];

View File

@@ -503,8 +503,10 @@ void DisplayManager_::loadNativeApps()
// Update the "hum" app at position 3
updateApp("hum", HumApp, SHOW_HUM, 3);
#ifdef ULANZI
// Update the "bat" app at position 4
updateApp("bat", BatApp, SHOW_BAT, 4);
#endif
ui.setApps(Apps);
@@ -813,11 +815,13 @@ void DisplayManager_::updateAppVector(const char *json)
callback = HumApp;
SHOW_HUM = show;
}
#ifdef ULANZI
else if (name == "bat")
{
callback = BatApp;
SHOW_BAT = show;
}
#endif
else
{
// If the app is not one of the built-in apps, check if it's already in the vector

View File

@@ -11,8 +11,10 @@ private:
DisplayManager_() = default;
#ifdef ULANZI
const int BatReadings = 10;
uint16_t TotalBatReadings[10];
#endif
int readIndex = 0;
uint16_t total = 0;
uint16_t average = 0;

View File

@@ -31,7 +31,9 @@ void loadSettings()
SHOW_DATE = Settings.getBool("DAT", true);
SHOW_TEMP = Settings.getBool("TEMP", true);
SHOW_HUM = Settings.getBool("HUM", true);
#ifdef ULANZI
SHOW_BAT = Settings.getBool("BAT", true);
#endif
Settings.end();
uniqueID = getID();
MQTT_PREFIX = String(uniqueID);
@@ -55,7 +57,9 @@ void saveSettings()
Settings.putBool("DAT", SHOW_DATE);
Settings.putBool("TEMP", SHOW_TEMP);
Settings.putBool("HUM", SHOW_HUM);
#ifdef ULANZI
Settings.putBool("BAT", SHOW_BAT);
#endif
Settings.end();
}
@@ -77,7 +81,9 @@ bool NET_STATIC = false;
bool SHOW_TIME = true;
bool SHOW_DATE = true;
bool SHOW_WEATHER = true;
#ifdef ULANZI
bool SHOW_BAT = true;
#endif
bool SHOW_TEMP = true;
bool SHOW_HUM = true;
bool SHOW_SECONDS = true;
@@ -102,8 +108,10 @@ float CURRENT_HUM;
float CURRENT_LUX;
uint8_t BRIGHTNESS = 120;
uint8_t BRIGHTNESS_PERCENT;
#ifdef ULANZI
uint8_t BATTERY_PERCENT;
uint16_t BATTERY_RAW;
#endif
uint16_t LDR_RAW;
String TIME_FORMAT = "%H:%M:%S";
String DATE_FORMAT = "%d.%m.%y";

View File

@@ -20,7 +20,9 @@ extern bool NET_STATIC;
extern bool SHOW_TIME;
extern bool SHOW_DATE;
extern bool SHOW_WEATHER;
#ifdef ULANZI
extern bool SHOW_BAT;
#endif
extern bool SHOW_TEMP;
extern bool SHOW_HUM;
extern bool SHOW_SECONDS;
@@ -42,8 +44,10 @@ extern float CURRENT_HUM;
extern float CURRENT_LUX;
extern uint16_t LDR_RAW;
extern String CURRENT_APP;
#ifdef ULANZI
extern uint8_t BATTERY_PERCENT;
extern uint16_t BATTERY_RAW;
#endif
extern uint8_t BRIGHTNESS;
extern uint8_t BRIGHTNESS_PERCENT;
extern String TEXTCOLOR;

View File

@@ -24,7 +24,9 @@ HAButton *nextApp = nullptr;
HAButton *prevApp = nullptr;
HASwitch *transition = nullptr;
HASensor *curApp = nullptr;
#ifdef ULANZI
HASensor *battery = nullptr;
#endif
HASensor *temperature = nullptr;
HASensor *humidity = nullptr;
HASensor *illuminance = nullptr;
@@ -238,7 +240,10 @@ void connect()
}
char matID[40], briID[40];
char btnAID[40], btnBID[40], btnCID[40], appID[40], tempID[40], humID[40], luxID[40], verID[40], batID[40], ramID[40], upID[40], sigID[40], btnLID[40], btnMID[40], btnRID[40], transID[40];
char btnAID[40], btnBID[40], btnCID[40], appID[40], tempID[40], humID[40], luxID[40], verID[40], ramID[40], upID[40], sigID[40], btnLID[40], btnMID[40], btnRID[40], transID[40];
#ifdef ULANZI
char batID[40];
#endif
void MQTTManager_::setup()
{
@@ -330,12 +335,14 @@ void MQTTManager_::setup()
humidity->setDeviceClass(HAhumClass);
humidity->setUnitOfMeasurement(HAhumUnit);
#ifdef ULANZI
sprintf(batID, HAbatID, macStr);
battery = new HASensor(batID);
battery->setIcon(HAbatIcon);
battery->setName(HAbatName);
battery->setDeviceClass(HAbatClass);
battery->setUnitOfMeasurement(HAbatUnit);
#endif
sprintf(luxID, HAluxID, macStr);
illuminance = new HASensor(luxID);
@@ -432,8 +439,10 @@ void MQTTManager_::sendStats()
if (HA_DISCOVERY)
{
char buffer[5];
#ifdef ULANZI
snprintf(buffer, 5, "%d", BATTERY_PERCENT);
battery->setValue(buffer);
#endif
snprintf(buffer, 5, "%.0f", CURRENT_TEMP);
temperature->setValue(buffer);
@@ -467,8 +476,10 @@ void MQTTManager_::sendStats()
StaticJsonDocument<200> doc;
char buffer[5];
#ifdef ULANZI
doc[BatKey] = BATTERY_PERCENT;
doc[BatRawKey] = BATTERY_RAW;
#endif
snprintf(buffer, 5, "%.0f", CURRENT_LUX);
doc[LuxKey] = buffer;
doc[LDRRawKey] = LDR_RAW;

View File

@@ -75,8 +75,13 @@ const char *appsItems[][2] PROGMEM = {
{"13", "time"},
{"1158", "date"},
{"234", "temp"},
#ifdef ULANZI
{"2075", "hum"},
{"1486", "bat"}};
#else
{"2075", "hum"}};
#endif
int8_t appsIndex;
uint8_t appsCount = 5;
@@ -173,9 +178,11 @@ String MenuManager_::menutext()
case 3:
DisplayManager.drawBMP(0, 0, get_icon(2075), 8, 8);
return SHOW_HUM ? "ON" : "OFF";
#ifdef ULANZI
case 4:
DisplayManager.drawBMP(0, 0, get_icon(1486), 8, 8);
return SHOW_BAT ? "ON" : "OFF";
#endif
default:
break;
}
@@ -374,9 +381,11 @@ void MenuManager_::selectButton()
case 3:
SHOW_HUM = !SHOW_HUM;
break;
#ifdef ULANZI
case 4:
SHOW_BAT = !SHOW_BAT;
break;
#endif
default:
break;
}

View File

@@ -21,7 +21,6 @@
#define BUTTON_SELECT_PIN 27
#else
// Pinouts für das WEMOS_D1_MINI32-Environment
#define BATTERY_PIN -1
#define BUZZER_PIN -1
#define LDR_PIN A0
#define BUTTON_UP_PIN D0
@@ -29,7 +28,11 @@
#define BUTTON_SELECT_PIN D8
#endif
#ifdef ULANZI
Adafruit_SHT31 sht31;
#else
Adafruit_BME280 bme280;
#endif
EasyButton button_left(BUTTON_UP_PIN);
EasyButton button_right(BUTTON_DOWN_PIN);
EasyButton button_select(BUTTON_SELECT_PIN);
@@ -134,11 +137,16 @@ bool PeripheryManager_::isPlaying()
void fistStart()
{
#ifdef ULANZI
uint16_t ADCVALUE = analogRead(BATTERY_PIN);
BATTERY_PERCENT = min((int)map(ADCVALUE, 490, 690, 0, 100), 100);
BATTERY_RAW = ADCVALUE;
sht31.readBoth(&CURRENT_TEMP, &CURRENT_HUM);
CURRENT_TEMP -= 9.0;
#else
CURRENT_TEMP = bme280.readTemperature();
CURRENT_HUM = 0;
#endif
uint16_t LDRVALUE = analogRead(LDR_PIN);
brightnessPercent = LDRVALUE / 4095.0 * 100.0;
@@ -160,7 +168,11 @@ void PeripheryManager_::setup()
button_select.onPressedFor(1000, select_button_pressed_long);
button_select.onSequence(2, 300, select_button_tripple);
Wire.begin(21, 22);
#ifdef ULANZI
sht31.begin(0x44);
#else
bme280.begin();
#endif
photocell.setPhotocellPositionOnGround(false);
fistStart();
}
@@ -176,11 +188,16 @@ void PeripheryManager_::tick()
if (currentMillis_BatTempHum - previousMillis_BatTempHum >= interval_BatTempHum)
{
previousMillis_BatTempHum = currentMillis_BatTempHum;
#ifdef ULANZI
uint16_t ADCVALUE = analogRead(BATTERY_PIN);
BATTERY_PERCENT = min((int)map(ADCVALUE, 475, 665, 0, 100), 100);
BATTERY_RAW = ADCVALUE;
sht31.readBoth(&CURRENT_TEMP, &CURRENT_HUM);
CURRENT_TEMP -= 9.0;
#else
CURRENT_TEMP = bme280.readTemperature();
CURRENT_HUM = bme280.readHumidity();
#endif
checkAlarms();
MQTTManager.sendStats();
}

View File

@@ -3,15 +3,21 @@
#include <Arduino.h>
#include <EasyButton.h>
#ifdef ULANZI
#include "Adafruit_SHT31.h"
#else
#include "Adafruit_BME280.h"
#endif
class PeripheryManager_
{
private:
PeripheryManager_() = default;
void checkAlarms();
#ifdef ULANZI
const int BatReadings = 10;
uint16_t TotalBatReadings[10];
#endif
int readIndex = 0;
uint16_t total = 0;
uint16_t average = 0;