2023-07-26 23:34:36 +00:00
|
|
|
/**
|
|
|
|
* @file ExternalNotificationModule.cpp
|
|
|
|
* @brief Implementation of the ExternalNotificationModule class.
|
2023-07-27 00:08:04 +00:00
|
|
|
*
|
|
|
|
* This file contains the implementation of the ExternalNotificationModule class, which is responsible for handling external
|
|
|
|
* notifications such as vibration, buzzer, and LED lights. The class provides methods to turn on and off the external
|
|
|
|
* notification outputs and to play ringtones using PWM buzzer. It also includes default configurations and a runOnce() method to
|
|
|
|
* handle the module's behavior.
|
|
|
|
*
|
2023-07-26 23:34:36 +00:00
|
|
|
* Documentation:
|
2023-11-06 22:03:44 +00:00
|
|
|
* https://meshtastic.org/docs/configuration/module/external-notification
|
2023-07-27 00:08:04 +00:00
|
|
|
*
|
2023-07-26 23:34:36 +00:00
|
|
|
* @author Jm Casler & Meshtastic Team
|
|
|
|
* @date [Insert Date]
|
|
|
|
*/
|
2022-02-27 08:18:35 +00:00
|
|
|
#include "ExternalNotificationModule.h"
|
2021-01-28 03:18:16 +00:00
|
|
|
#include "MeshService.h"
|
|
|
|
#include "NodeDB.h"
|
|
|
|
#include "RTC.h"
|
|
|
|
#include "Router.h"
|
2022-10-22 11:35:34 +00:00
|
|
|
#include "buzz/buzz.h"
|
2022-05-07 10:31:21 +00:00
|
|
|
#include "configuration.h"
|
2023-12-12 14:36:37 +00:00
|
|
|
#include "main.h"
|
2023-01-18 14:56:47 +00:00
|
|
|
#include "mesh/generated/meshtastic/rtttl.pb.h"
|
2021-01-28 03:18:16 +00:00
|
|
|
#include <Arduino.h>
|
|
|
|
|
2023-07-03 14:34:32 +00:00
|
|
|
#ifdef HAS_NCP5623
|
2023-06-27 00:59:44 +00:00
|
|
|
#include <graphics/RAKled.h>
|
2023-05-06 12:17:40 +00:00
|
|
|
|
|
|
|
uint8_t red = 0;
|
|
|
|
uint8_t green = 0;
|
|
|
|
uint8_t blue = 0;
|
2023-11-07 05:43:30 +00:00
|
|
|
uint8_t colorState = 1;
|
|
|
|
uint8_t brightnessIndex = 0;
|
|
|
|
uint8_t brightnessValues[] = {0, 10, 20, 30, 50, 90, 160, 170}; // blue gets multiplied by 1.5
|
|
|
|
bool ascending = true;
|
2023-05-06 12:17:40 +00:00
|
|
|
#endif
|
|
|
|
|
2022-10-22 11:35:34 +00:00
|
|
|
#ifndef PIN_BUZZER
|
|
|
|
#define PIN_BUZZER false
|
|
|
|
#endif
|
|
|
|
|
2021-01-28 03:18:16 +00:00
|
|
|
/*
|
2021-01-30 17:36:17 +00:00
|
|
|
Documentation:
|
2023-11-06 22:03:44 +00:00
|
|
|
https://meshtastic.org/docs/configuration/module/external-notification
|
2021-01-28 03:18:16 +00:00
|
|
|
*/
|
|
|
|
|
2021-01-30 17:17:40 +00:00
|
|
|
// Default configurations
|
2022-10-22 12:13:45 +00:00
|
|
|
#ifdef EXT_NOTIFY_OUT
|
2022-02-27 09:49:24 +00:00
|
|
|
#define EXT_NOTIFICATION_MODULE_OUTPUT EXT_NOTIFY_OUT
|
2022-10-22 12:13:45 +00:00
|
|
|
#else
|
|
|
|
#define EXT_NOTIFICATION_MODULE_OUTPUT 0
|
|
|
|
#endif
|
2022-02-27 09:49:24 +00:00
|
|
|
#define EXT_NOTIFICATION_MODULE_OUTPUT_MS 1000
|
2021-01-28 05:20:18 +00:00
|
|
|
|
2023-12-12 14:36:37 +00:00
|
|
|
#define EXT_NOTIFICATION_DEFAULT_THREAD_MS 25
|
|
|
|
|
2021-01-28 05:20:18 +00:00
|
|
|
#define ASCII_BELL 0x07
|
|
|
|
|
2023-01-21 17:22:19 +00:00
|
|
|
meshtastic_RTTTLConfig rtttlConfig;
|
2022-12-29 15:53:36 +00:00
|
|
|
|
2022-12-08 15:27:56 +00:00
|
|
|
ExternalNotificationModule *externalNotificationModule;
|
|
|
|
|
|
|
|
bool externalCurrentState[3] = {};
|
|
|
|
|
|
|
|
uint32_t externalTurnedOn[3] = {};
|
2021-01-29 07:02:00 +00:00
|
|
|
|
2022-12-29 15:53:36 +00:00
|
|
|
static const char *rtttlConfigFile = "/prefs/ringtone.proto";
|
|
|
|
|
2022-02-27 09:49:24 +00:00
|
|
|
int32_t ExternalNotificationModule::runOnce()
|
2021-01-28 03:18:16 +00:00
|
|
|
{
|
2022-12-28 13:57:40 +00:00
|
|
|
if (!moduleConfig.external_notification.enabled) {
|
2022-12-08 15:27:56 +00:00
|
|
|
return INT32_MAX; // we don't need this thread here...
|
|
|
|
} else {
|
2023-12-12 14:36:37 +00:00
|
|
|
|
|
|
|
bool isPlaying = rtttl::isPlaying();
|
|
|
|
#ifdef HAS_I2S
|
|
|
|
isPlaying = rtttl::isPlaying() || audioThread->isPlaying();
|
|
|
|
#endif
|
|
|
|
if ((nagCycleCutoff < millis()) && !isPlaying) {
|
2023-01-04 13:45:28 +00:00
|
|
|
// let the song finish if we reach timeout
|
2022-12-27 20:51:35 +00:00
|
|
|
nagCycleCutoff = UINT32_MAX;
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("Turning off external notification: ");
|
2022-12-27 20:51:35 +00:00
|
|
|
for (int i = 0; i < 2; i++) {
|
2023-01-04 13:45:28 +00:00
|
|
|
setExternalOff(i);
|
|
|
|
externalTurnedOn[i] = 0;
|
|
|
|
LOG_INFO("%d ", i);
|
2022-12-27 20:51:35 +00:00
|
|
|
}
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("\n");
|
2023-01-04 13:45:28 +00:00
|
|
|
isNagging = false;
|
2022-12-27 20:51:35 +00:00
|
|
|
return INT32_MAX; // save cycles till we're needed again
|
|
|
|
}
|
|
|
|
|
2021-03-13 05:32:23 +00:00
|
|
|
// If the output is turned on, turn it back off after the given period of time.
|
2023-01-04 13:45:28 +00:00
|
|
|
if (isNagging) {
|
2023-01-18 20:51:48 +00:00
|
|
|
if (externalTurnedOn[0] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms
|
|
|
|
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
|
|
|
|
millis()) {
|
2022-12-08 15:27:56 +00:00
|
|
|
getExternal(0) ? setExternalOff(0) : setExternalOn(0);
|
|
|
|
}
|
2023-01-18 20:51:48 +00:00
|
|
|
if (externalTurnedOn[1] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms
|
|
|
|
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
|
|
|
|
millis()) {
|
2022-12-08 15:27:56 +00:00
|
|
|
getExternal(1) ? setExternalOff(1) : setExternalOn(1);
|
|
|
|
}
|
2023-01-18 20:51:48 +00:00
|
|
|
if (externalTurnedOn[2] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms
|
|
|
|
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
|
|
|
|
millis()) {
|
2022-12-08 15:27:56 +00:00
|
|
|
getExternal(2) ? setExternalOff(2) : setExternalOn(2);
|
|
|
|
}
|
2023-07-03 14:34:32 +00:00
|
|
|
#ifdef HAS_NCP5623
|
2023-05-06 12:17:40 +00:00
|
|
|
if (rgb_found.type == ScanI2C::NCP5623) {
|
2023-11-07 05:43:30 +00:00
|
|
|
red = (colorState & 4) ? brightnessValues[brightnessIndex] : 0; // Red enabled on colorState = 4,5,6,7
|
|
|
|
green = (colorState & 2) ? brightnessValues[brightnessIndex] : 0; // Green enabled on colorState = 2,3,6,7
|
|
|
|
blue = (colorState & 1) ? (brightnessValues[brightnessIndex] * 1.5) : 0; // Blue enabled on colorState = 1,3,5,7
|
2023-05-06 12:17:40 +00:00
|
|
|
rgb.setColor(red, green, blue);
|
2023-11-07 05:43:30 +00:00
|
|
|
|
|
|
|
if (ascending) { // fade in
|
|
|
|
brightnessIndex++;
|
2023-11-08 05:46:18 +00:00
|
|
|
if (brightnessIndex == (sizeof(brightnessValues) - 1)) {
|
2023-11-07 05:43:30 +00:00
|
|
|
ascending = false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
brightnessIndex--; // fade out
|
|
|
|
}
|
|
|
|
if (brightnessIndex == 0) {
|
|
|
|
ascending = true;
|
|
|
|
colorState++; // next color
|
|
|
|
if (colorState > 7) {
|
|
|
|
colorState = 1;
|
|
|
|
}
|
|
|
|
}
|
2023-05-06 12:17:40 +00:00
|
|
|
}
|
|
|
|
#endif
|
2023-07-22 14:26:54 +00:00
|
|
|
|
|
|
|
#ifdef T_WATCH_S3
|
|
|
|
drv.go();
|
|
|
|
#endif
|
2022-12-08 15:27:56 +00:00
|
|
|
}
|
2022-12-28 13:57:40 +00:00
|
|
|
|
2023-12-12 14:36:37 +00:00
|
|
|
// Play RTTTL over i2s audio interface if enabled as buzzer
|
|
|
|
#ifdef HAS_I2S
|
|
|
|
if (moduleConfig.external_notification.use_i2s_as_buzzer) {
|
|
|
|
if (audioThread->isPlaying()) {
|
|
|
|
// Continue playing
|
|
|
|
} else if (isNagging && (nagCycleCutoff >= millis())) {
|
|
|
|
audioThread->beginRttl(rtttlConfig.ringtone, strlen_P(rtttlConfig.ringtone));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2022-12-28 13:57:40 +00:00
|
|
|
// now let the PWM buzzer play
|
|
|
|
if (moduleConfig.external_notification.use_pwm) {
|
|
|
|
if (rtttl::isPlaying()) {
|
|
|
|
rtttl::play();
|
2023-01-04 13:45:28 +00:00
|
|
|
} else if (isNagging && (nagCycleCutoff >= millis())) {
|
2022-12-28 13:57:40 +00:00
|
|
|
// start the song again if we have time left
|
2022-12-29 15:53:36 +00:00
|
|
|
rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone);
|
2022-12-28 13:57:40 +00:00
|
|
|
}
|
|
|
|
}
|
2023-05-06 12:17:40 +00:00
|
|
|
|
2023-12-12 14:36:37 +00:00
|
|
|
return EXT_NOTIFICATION_DEFAULT_THREAD_MS;
|
2022-12-08 15:27:56 +00:00
|
|
|
}
|
2021-01-28 03:18:16 +00:00
|
|
|
}
|
|
|
|
|
2023-08-19 12:46:34 +00:00
|
|
|
bool ExternalNotificationModule::wantPacket(const meshtastic_MeshPacket *p)
|
|
|
|
{
|
|
|
|
return MeshService::isTextPayload(p);
|
|
|
|
}
|
|
|
|
|
2023-07-26 23:34:36 +00:00
|
|
|
/**
|
|
|
|
* Sets the external notification on for the specified index.
|
|
|
|
*
|
|
|
|
* @param index The index of the external notification to turn on.
|
|
|
|
*/
|
2022-12-08 15:27:56 +00:00
|
|
|
void ExternalNotificationModule::setExternalOn(uint8_t index)
|
2021-01-28 04:06:39 +00:00
|
|
|
{
|
2022-12-08 15:27:56 +00:00
|
|
|
externalCurrentState[index] = 1;
|
|
|
|
externalTurnedOn[index] = millis();
|
|
|
|
|
2023-01-18 20:51:48 +00:00
|
|
|
switch (index) {
|
|
|
|
case 1:
|
|
|
|
if (moduleConfig.external_notification.output_vibra)
|
|
|
|
digitalWrite(moduleConfig.external_notification.output_vibra, true);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (moduleConfig.external_notification.output_buzzer)
|
|
|
|
digitalWrite(moduleConfig.external_notification.output_buzzer, true);
|
|
|
|
break;
|
|
|
|
default:
|
2023-07-22 14:26:54 +00:00
|
|
|
if (output > 0)
|
|
|
|
digitalWrite(output, (moduleConfig.external_notification.active ? true : false));
|
2023-01-18 20:51:48 +00:00
|
|
|
break;
|
2022-12-08 15:27:56 +00:00
|
|
|
}
|
2023-12-12 14:36:37 +00:00
|
|
|
|
2023-07-03 14:34:32 +00:00
|
|
|
#ifdef HAS_NCP5623
|
2023-05-06 12:17:40 +00:00
|
|
|
if (rgb_found.type == ScanI2C::NCP5623) {
|
|
|
|
rgb.setColor(red, green, blue);
|
|
|
|
}
|
|
|
|
#endif
|
2023-07-22 14:26:54 +00:00
|
|
|
#ifdef T_WATCH_S3
|
|
|
|
drv.go();
|
|
|
|
#endif
|
2021-01-28 04:06:39 +00:00
|
|
|
}
|
|
|
|
|
2022-12-08 15:27:56 +00:00
|
|
|
void ExternalNotificationModule::setExternalOff(uint8_t index)
|
2021-01-28 04:06:39 +00:00
|
|
|
{
|
2022-12-08 15:27:56 +00:00
|
|
|
externalCurrentState[index] = 0;
|
|
|
|
externalTurnedOn[index] = millis();
|
|
|
|
|
2023-01-18 20:51:48 +00:00
|
|
|
switch (index) {
|
|
|
|
case 1:
|
|
|
|
if (moduleConfig.external_notification.output_vibra)
|
|
|
|
digitalWrite(moduleConfig.external_notification.output_vibra, false);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (moduleConfig.external_notification.output_buzzer)
|
|
|
|
digitalWrite(moduleConfig.external_notification.output_buzzer, false);
|
|
|
|
break;
|
|
|
|
default:
|
2023-07-22 14:26:54 +00:00
|
|
|
if (output > 0)
|
|
|
|
digitalWrite(output, (moduleConfig.external_notification.active ? false : true));
|
2023-01-18 20:51:48 +00:00
|
|
|
break;
|
2022-12-08 15:27:56 +00:00
|
|
|
}
|
2023-05-06 12:17:40 +00:00
|
|
|
|
2023-07-03 14:34:32 +00:00
|
|
|
#ifdef HAS_NCP5623
|
2023-05-06 12:17:40 +00:00
|
|
|
if (rgb_found.type == ScanI2C::NCP5623) {
|
|
|
|
red = 0;
|
|
|
|
green = 0;
|
|
|
|
blue = 0;
|
|
|
|
rgb.setColor(red, green, blue);
|
|
|
|
}
|
|
|
|
#endif
|
2023-07-22 14:26:54 +00:00
|
|
|
#ifdef T_WATCH_S3
|
|
|
|
drv.stop();
|
|
|
|
#endif
|
2022-12-08 15:27:56 +00:00
|
|
|
}
|
2021-01-28 05:20:18 +00:00
|
|
|
|
2022-12-08 15:27:56 +00:00
|
|
|
bool ExternalNotificationModule::getExternal(uint8_t index)
|
|
|
|
{
|
|
|
|
return externalCurrentState[index];
|
2021-01-28 04:06:39 +00:00
|
|
|
}
|
|
|
|
|
2023-01-18 20:51:48 +00:00
|
|
|
void ExternalNotificationModule::stopNow()
|
|
|
|
{
|
2022-12-28 13:57:40 +00:00
|
|
|
rtttl::stop();
|
2023-12-12 14:36:37 +00:00
|
|
|
#ifdef HAS_I2S
|
|
|
|
audioThread->stop();
|
|
|
|
#endif
|
2022-12-28 13:57:40 +00:00
|
|
|
nagCycleCutoff = 1; // small value
|
2023-01-04 13:45:28 +00:00
|
|
|
isNagging = false;
|
2022-12-28 13:57:40 +00:00
|
|
|
setIntervalFromNow(0);
|
2023-07-22 14:26:54 +00:00
|
|
|
#ifdef T_WATCH_S3
|
|
|
|
drv.stop();
|
|
|
|
#endif
|
2022-12-28 13:57:40 +00:00
|
|
|
}
|
2021-01-28 03:18:16 +00:00
|
|
|
|
2022-02-27 09:49:24 +00:00
|
|
|
ExternalNotificationModule::ExternalNotificationModule()
|
2023-08-19 12:46:34 +00:00
|
|
|
: SinglePortModule("ExternalNotificationModule", meshtastic_PortNum_TEXT_MESSAGE_APP),
|
|
|
|
concurrency::OSThread("ExternalNotificationModule")
|
2021-03-13 05:32:23 +00:00
|
|
|
{
|
|
|
|
/*
|
2022-02-27 09:49:24 +00:00
|
|
|
Uncomment the preferences below if you want to use the module
|
2021-03-13 05:32:23 +00:00
|
|
|
without having to configure it from the PythonAPI or WebUI.
|
|
|
|
*/
|
|
|
|
|
2022-12-16 19:33:09 +00:00
|
|
|
// moduleConfig.external_notification.alert_message = true;
|
|
|
|
// moduleConfig.external_notification.alert_message_buzzer = true;
|
|
|
|
// moduleConfig.external_notification.alert_message_vibra = true;
|
2023-12-12 14:36:37 +00:00
|
|
|
// moduleConfig.external_notification.use_i2s_as_buzzer = true;
|
2021-03-13 05:32:23 +00:00
|
|
|
|
2022-12-16 19:33:09 +00:00
|
|
|
// moduleConfig.external_notification.active = true;
|
2022-05-22 11:27:56 +00:00
|
|
|
// moduleConfig.external_notification.alert_bell = 1;
|
|
|
|
// moduleConfig.external_notification.output_ms = 1000;
|
2022-12-16 19:33:09 +00:00
|
|
|
// moduleConfig.external_notification.output = 4; // RAK4631 IO4
|
|
|
|
// moduleConfig.external_notification.output_buzzer = 10; // RAK4631 IO6
|
|
|
|
// moduleConfig.external_notification.output_vibra = 28; // RAK4631 IO7
|
|
|
|
// moduleConfig.external_notification.nag_timeout = 300;
|
2023-01-18 20:51:48 +00:00
|
|
|
|
2023-12-12 14:36:37 +00:00
|
|
|
// T-Watch / T-Deck i2s audio as buzzer:
|
|
|
|
// moduleConfig.external_notification.enabled = true;
|
|
|
|
// moduleConfig.external_notification.nag_timeout = 300;
|
|
|
|
// moduleConfig.external_notification.output_ms = 1000;
|
|
|
|
// moduleConfig.external_notification.use_i2s_as_buzzer = true;
|
|
|
|
// moduleConfig.external_notification.alert_message_buzzer = true;
|
|
|
|
|
2022-05-22 11:27:56 +00:00
|
|
|
if (moduleConfig.external_notification.enabled) {
|
2023-01-21 17:39:58 +00:00
|
|
|
if (!nodeDB.loadProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, sizeof(meshtastic_RTTTLConfig),
|
|
|
|
&meshtastic_RTTTLConfig_msg, &rtttlConfig)) {
|
2022-12-29 15:53:36 +00:00
|
|
|
memset(rtttlConfig.ringtone, 0, sizeof(rtttlConfig.ringtone));
|
2023-01-18 20:51:48 +00:00
|
|
|
strncpy(rtttlConfig.ringtone,
|
2024-01-19 19:41:24 +00:00
|
|
|
"24:d=32,o=5,b=565:f6,p,f6,4p,p,f6,p,f6,2p,p,b6,p,b6,p,b6,p,b6,p,b,p,b,p,b,p,b,p,b,p,b,p,b,p,b,1p.,2p.,p",
|
2023-01-18 20:51:48 +00:00
|
|
|
sizeof(rtttlConfig.ringtone));
|
2022-12-29 15:53:36 +00:00
|
|
|
}
|
2021-03-13 05:32:23 +00:00
|
|
|
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("Initializing External Notification Module\n");
|
2021-03-13 05:32:23 +00:00
|
|
|
|
2023-01-18 20:51:48 +00:00
|
|
|
output = moduleConfig.external_notification.output ? moduleConfig.external_notification.output
|
|
|
|
: EXT_NOTIFICATION_MODULE_OUTPUT;
|
2021-03-13 05:32:23 +00:00
|
|
|
|
2022-12-28 13:57:40 +00:00
|
|
|
// Set the direction of a pin
|
2023-07-22 14:26:54 +00:00
|
|
|
if (output > 0) {
|
|
|
|
LOG_INFO("Using Pin %i in digital mode\n", output);
|
|
|
|
pinMode(output, OUTPUT);
|
|
|
|
}
|
2022-12-28 13:57:40 +00:00
|
|
|
setExternalOff(0);
|
|
|
|
externalTurnedOn[0] = 0;
|
2023-01-18 20:51:48 +00:00
|
|
|
if (moduleConfig.external_notification.output_vibra) {
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("Using Pin %i for vibra motor\n", moduleConfig.external_notification.output_vibra);
|
2022-12-28 13:57:40 +00:00
|
|
|
pinMode(moduleConfig.external_notification.output_vibra, OUTPUT);
|
|
|
|
setExternalOff(1);
|
|
|
|
externalTurnedOn[1] = 0;
|
|
|
|
}
|
2023-01-18 20:51:48 +00:00
|
|
|
if (moduleConfig.external_notification.output_buzzer) {
|
2022-12-28 13:57:40 +00:00
|
|
|
if (!moduleConfig.external_notification.use_pwm) {
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("Using Pin %i for buzzer\n", moduleConfig.external_notification.output_buzzer);
|
2022-12-08 15:27:56 +00:00
|
|
|
pinMode(moduleConfig.external_notification.output_buzzer, OUTPUT);
|
|
|
|
setExternalOff(2);
|
|
|
|
externalTurnedOn[2] = 0;
|
2022-12-28 13:57:40 +00:00
|
|
|
} else {
|
2023-01-18 20:51:48 +00:00
|
|
|
config.device.buzzer_gpio = config.device.buzzer_gpio ? config.device.buzzer_gpio : PIN_BUZZER;
|
2022-12-28 13:57:40 +00:00
|
|
|
// in PWM Mode we force the buzzer pin if it is set
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("Using Pin %i in PWM mode\n", config.device.buzzer_gpio);
|
2022-12-08 15:27:56 +00:00
|
|
|
}
|
2022-10-22 11:35:34 +00:00
|
|
|
}
|
2023-07-03 14:34:32 +00:00
|
|
|
#ifdef HAS_NCP5623
|
2023-05-06 12:17:40 +00:00
|
|
|
if (rgb_found.type == ScanI2C::NCP5623) {
|
|
|
|
rgb.begin();
|
|
|
|
rgb.setCurrent(10);
|
|
|
|
}
|
|
|
|
#endif
|
2021-03-13 05:32:23 +00:00
|
|
|
} else {
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("External Notification Module Disabled\n");
|
2022-12-29 22:26:25 +00:00
|
|
|
disable();
|
2021-03-13 05:32:23 +00:00
|
|
|
}
|
2021-03-13 05:14:27 +00:00
|
|
|
}
|
|
|
|
|
2023-01-21 17:22:19 +00:00
|
|
|
ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshPacket &mp)
|
2021-01-28 03:18:16 +00:00
|
|
|
{
|
2022-05-22 11:27:56 +00:00
|
|
|
if (moduleConfig.external_notification.enabled) {
|
2023-12-12 14:36:37 +00:00
|
|
|
#ifdef T_WATCH_S3
|
2023-07-22 14:26:54 +00:00
|
|
|
drv.setWaveform(0, 75);
|
|
|
|
drv.setWaveform(1, 56);
|
|
|
|
drv.setWaveform(2, 0);
|
|
|
|
drv.go();
|
|
|
|
#endif
|
2021-03-05 02:19:27 +00:00
|
|
|
if (getFrom(&mp) != nodeDB.getNodeNum()) {
|
2022-12-08 15:27:56 +00:00
|
|
|
// Check if the message contains a bell character. Don't do this loop for every pin, just once.
|
|
|
|
auto &p = mp.decoded;
|
|
|
|
bool containsBell = false;
|
|
|
|
for (int i = 0; i < p.payload.size; i++) {
|
|
|
|
if (p.payload.bytes[i] == ASCII_BELL) {
|
|
|
|
containsBell = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-22 11:27:56 +00:00
|
|
|
if (moduleConfig.external_notification.alert_bell) {
|
2022-12-08 15:27:56 +00:00
|
|
|
if (containsBell) {
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("externalNotificationModule - Notification Bell\n");
|
2023-01-04 13:45:28 +00:00
|
|
|
isNagging = true;
|
2022-12-28 13:57:40 +00:00
|
|
|
setExternalOn(0);
|
|
|
|
if (moduleConfig.external_notification.nag_timeout) {
|
|
|
|
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
2022-12-08 15:27:56 +00:00
|
|
|
} else {
|
2022-12-28 13:57:40 +00:00
|
|
|
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
2022-12-08 15:27:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-28 13:57:40 +00:00
|
|
|
if (moduleConfig.external_notification.alert_bell_vibra) {
|
|
|
|
if (containsBell) {
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("externalNotificationModule - Notification Bell (Vibra)\n");
|
2023-01-04 13:45:28 +00:00
|
|
|
isNagging = true;
|
2022-12-28 13:57:40 +00:00
|
|
|
setExternalOn(1);
|
|
|
|
if (moduleConfig.external_notification.nag_timeout) {
|
|
|
|
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
|
|
|
} else {
|
|
|
|
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
2022-12-08 15:27:56 +00:00
|
|
|
}
|
|
|
|
}
|
2022-12-28 13:57:40 +00:00
|
|
|
}
|
2022-12-08 15:27:56 +00:00
|
|
|
|
2022-12-28 13:57:40 +00:00
|
|
|
if (moduleConfig.external_notification.alert_bell_buzzer) {
|
|
|
|
if (containsBell) {
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("externalNotificationModule - Notification Bell (Buzzer)\n");
|
2023-01-04 13:45:28 +00:00
|
|
|
isNagging = true;
|
2022-12-28 13:57:40 +00:00
|
|
|
if (!moduleConfig.external_notification.use_pwm) {
|
2022-12-08 15:27:56 +00:00
|
|
|
setExternalOn(2);
|
2022-12-28 13:57:40 +00:00
|
|
|
} else {
|
2023-12-12 14:36:37 +00:00
|
|
|
#ifdef HAS_I2S
|
|
|
|
audioThread->beginRttl(rtttlConfig.ringtone, strlen_P(rtttlConfig.ringtone));
|
|
|
|
#else
|
2022-12-29 15:53:36 +00:00
|
|
|
rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone);
|
2023-12-12 14:36:37 +00:00
|
|
|
#endif
|
2021-01-28 05:20:18 +00:00
|
|
|
}
|
2022-12-08 15:27:56 +00:00
|
|
|
if (moduleConfig.external_notification.nag_timeout) {
|
|
|
|
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
|
|
|
} else {
|
|
|
|
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
|
|
|
}
|
2022-12-28 13:57:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (moduleConfig.external_notification.alert_message) {
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("externalNotificationModule - Notification Module\n");
|
2023-01-04 13:45:28 +00:00
|
|
|
isNagging = true;
|
2022-12-28 13:57:40 +00:00
|
|
|
setExternalOn(0);
|
|
|
|
if (moduleConfig.external_notification.nag_timeout) {
|
|
|
|
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
2022-10-22 11:35:34 +00:00
|
|
|
} else {
|
2022-12-28 13:57:40 +00:00
|
|
|
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
2022-10-22 11:35:34 +00:00
|
|
|
}
|
2021-01-28 05:20:18 +00:00
|
|
|
}
|
2022-12-08 15:27:56 +00:00
|
|
|
|
2023-01-04 13:45:28 +00:00
|
|
|
if (moduleConfig.external_notification.alert_message_vibra) {
|
|
|
|
LOG_INFO("externalNotificationModule - Notification Module (Vibra)\n");
|
|
|
|
isNagging = true;
|
|
|
|
setExternalOn(1);
|
|
|
|
if (moduleConfig.external_notification.nag_timeout) {
|
|
|
|
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
|
|
|
} else {
|
|
|
|
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
2022-12-08 15:27:56 +00:00
|
|
|
}
|
2023-01-04 13:45:28 +00:00
|
|
|
}
|
2022-12-08 15:27:56 +00:00
|
|
|
|
2023-01-04 13:45:28 +00:00
|
|
|
if (moduleConfig.external_notification.alert_message_buzzer) {
|
|
|
|
LOG_INFO("externalNotificationModule - Notification Module (Buzzer)\n");
|
|
|
|
isNagging = true;
|
2023-12-12 14:36:37 +00:00
|
|
|
if (!moduleConfig.external_notification.use_pwm && !moduleConfig.external_notification.use_i2s_as_buzzer) {
|
2023-01-04 13:45:28 +00:00
|
|
|
setExternalOn(2);
|
|
|
|
} else {
|
2023-12-12 14:36:37 +00:00
|
|
|
#ifdef HAS_I2S
|
|
|
|
if (moduleConfig.external_notification.use_i2s_as_buzzer) {
|
|
|
|
audioThread->beginRttl(rtttlConfig.ringtone, strlen_P(rtttlConfig.ringtone));
|
|
|
|
}
|
|
|
|
#else
|
2023-01-04 13:45:28 +00:00
|
|
|
rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone);
|
2023-12-12 14:36:37 +00:00
|
|
|
#endif
|
2023-01-04 13:45:28 +00:00
|
|
|
}
|
|
|
|
if (moduleConfig.external_notification.nag_timeout) {
|
|
|
|
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
|
|
|
} else {
|
|
|
|
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
2022-12-08 15:27:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
setIntervalFromNow(0); // run once so we know if we should do something
|
2021-01-28 03:18:16 +00:00
|
|
|
}
|
|
|
|
} else {
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("External Notification Module Disabled\n");
|
2021-01-28 03:18:16 +00:00
|
|
|
}
|
|
|
|
|
2021-09-23 01:42:09 +00:00
|
|
|
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
2021-01-28 03:18:16 +00:00
|
|
|
}
|
2022-12-29 15:53:36 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief An admin message arrived to AdminModule. We are asked whether we want to handle that.
|
|
|
|
*
|
|
|
|
* @param mp The mesh packet arrived.
|
|
|
|
* @param request The AdminMessage request extracted from the packet.
|
|
|
|
* @param response The prepared response
|
|
|
|
* @return AdminMessageHandleResult HANDLED if message was handled
|
|
|
|
* HANDLED_WITH_RESULT if a result is also prepared.
|
|
|
|
*/
|
2023-01-21 17:39:58 +00:00
|
|
|
AdminMessageHandleResult ExternalNotificationModule::handleAdminMessageForModule(const meshtastic_MeshPacket &mp,
|
|
|
|
meshtastic_AdminMessage *request,
|
2023-01-21 17:22:19 +00:00
|
|
|
meshtastic_AdminMessage *response)
|
2022-12-29 15:53:36 +00:00
|
|
|
{
|
|
|
|
AdminMessageHandleResult result;
|
|
|
|
|
|
|
|
switch (request->which_payload_variant) {
|
2023-01-21 17:22:19 +00:00
|
|
|
case meshtastic_AdminMessage_get_ringtone_request_tag:
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("Client is getting ringtone\n");
|
2022-12-29 15:53:36 +00:00
|
|
|
this->handleGetRingtone(mp, response);
|
|
|
|
result = AdminMessageHandleResult::HANDLED_WITH_RESPONSE;
|
|
|
|
break;
|
|
|
|
|
2023-01-21 17:22:19 +00:00
|
|
|
case meshtastic_AdminMessage_set_ringtone_message_tag:
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("Client is setting ringtone\n");
|
2022-12-29 15:53:36 +00:00
|
|
|
this->handleSetRingtone(request->set_canned_message_module_messages);
|
|
|
|
result = AdminMessageHandleResult::HANDLED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
result = AdminMessageHandleResult::NOT_HANDLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-01-21 17:22:19 +00:00
|
|
|
void ExternalNotificationModule::handleGetRingtone(const meshtastic_MeshPacket &req, meshtastic_AdminMessage *response)
|
2022-12-29 15:53:36 +00:00
|
|
|
{
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("*** handleGetRingtone\n");
|
2023-01-18 20:51:48 +00:00
|
|
|
if (req.decoded.want_response) {
|
2023-01-21 17:22:19 +00:00
|
|
|
response->which_payload_variant = meshtastic_AdminMessage_get_ringtone_response_tag;
|
2023-01-16 09:55:40 +00:00
|
|
|
strncpy(response->get_ringtone_response, rtttlConfig.ringtone, sizeof(response->get_ringtone_response));
|
2023-01-07 14:24:46 +00:00
|
|
|
} // Don't send anything if not instructed to. Better than asserting.
|
2022-12-29 15:53:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ExternalNotificationModule::handleSetRingtone(const char *from_msg)
|
|
|
|
{
|
|
|
|
int changed = 0;
|
|
|
|
|
|
|
|
if (*from_msg) {
|
|
|
|
changed |= strcmp(rtttlConfig.ringtone, from_msg);
|
2023-01-16 09:55:40 +00:00
|
|
|
strncpy(rtttlConfig.ringtone, from_msg, sizeof(rtttlConfig.ringtone));
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_INFO("*** from_msg.text:%s\n", from_msg);
|
2022-12-29 15:53:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (changed) {
|
2023-01-21 17:22:19 +00:00
|
|
|
nodeDB.saveProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, &meshtastic_RTTTLConfig_msg, &rtttlConfig);
|
2022-12-29 15:53:36 +00:00
|
|
|
}
|
|
|
|
}
|