Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
|
When I work concentrated, I often forget what's the time and miss appointments or I'm late. Because I don't look at a watch my RasPi Device reminds me and makes an announcement every 20 minutes. The app runs in background and starts when the device is powered on. No monitor is necessary.
For a little bit of monitoring a log file is written to D: in the format like TimeTalkerLog2018-Feb-25.log
To Do:
- At the moment the time-period between the announcements is hard coded with 20 minutes. In the next step this period shall be configurable with an ini-file. The advantage of the ini-file would be, that you can plug-in the sd-card into your PC and configure with a text editor without the need of a network-connection to the RasPi. After that, the configuration shall be possible over a web service. For that a network-connection is necessary.
- Configuration of the voice and language shall be possible through ini-file or web interface, too.
- Switching to rotating logs would be comfortable
using System;
using Windows.ApplicationModel.Background;
using System.Threading;
// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409
namespace TimeTalkerBackground
{
public sealed class StartupTask : IBackgroundTask
{
private BackgroundTaskDeferral deferral;
private Timer clockTimer;
private SpeechService speechService;
public async void Run(IBackgroundTaskInstance taskInstance)
{
//
// TODO: Insert code to perform background work
//
// If you start any asynchronous methods here, prevent the task
// from closing prematurely by using BackgroundTaskDeferral as
// described in http://aka.ms/backgroundtaskdeferral
//
deferral = taskInstance.GetDeferral();
Logging.LogIni();
Logging.ToFile("Starting SpeechService. ");
speechService = new SpeechService();
await speechService.SayIntroText();
Logging.ToFile("Waiting a little bit until Intro is finished. ");
System.Threading.Thread.Sleep(7000);
Logging.ToFile("Waiting Done. I go on. ");
speechService = new SpeechService();
var timeToNextCall = GetTimeSpanToNextCall();
clockTimer = new Timer(OnClock, null, timeToNextCall, TimeSpan.FromMinutes(20));
await speechService.SayTimeEn();
}
private static TimeSpan GetTimeSpanToNextCall()
{
var now = DateTime.Now;
var nextCall = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0).AddMinutes(20);
return nextCall - now;
}
private async void OnClock(object state)
{
await speechService.SayTimeEn();
/*
* This line would fit for german language and the text is prepared in speechService.SayTimeDe()
*
* await speechService.SayTimeDe();
*
*/
}
}
}
using System;
using System.Linq;
using System.Threading.Tasks;
using Windows.Media.Core;
using Windows.Media.SpeechSynthesis;
namespace TimeTalkerBackground
{
internal class SpeechService
{
private readonly SpeechSynthesizer speechSynthesizer;
private readonly Windows.Media.Playback.MediaPlayer speechPlayer;
public SpeechService()
{
speechSynthesizer = CreateSpeechSynthesizer();
speechPlayer = new Windows.Media.Playback.MediaPlayer();
}
public async Task SayAsync(string text)
{
using (var stream = await speechSynthesizer.SynthesizeTextToStreamAsync(text))
{
speechPlayer.Source = MediaSource.CreateFromStream(stream, stream.ContentType);
}
speechPlayer.Play();
Logging.ToFile("speechPlayer said: "+text);
}
private static SpeechSynthesizer CreateSpeechSynthesizer()
{
var synthesizer = new SpeechSynthesizer();
/*
* my favourite voice for german language
* var voice = SpeechSynthesizer.AllVoices.FirstOrDefault(i => i.Gender == VoiceGender.Female && i.DisplayName == "Microsoft Katja") ?? SpeechSynthesizer.DefaultVoice;
*/
var voice = SpeechSynthesizer.AllVoices.FirstOrDefault(i => i.Gender == VoiceGender.Female && i.DisplayName == "Microsoft Zira") ?? SpeechSynthesizer.DefaultVoice;
synthesizer.Voice = voice;
Logging.ToFile($"{voice.DisplayName} ({voice.Language}), {voice.Gender}, {voice.Description}, {voice.Id} ");
Logging.ToFile("SpeechSynthesizer created. ");
return synthesizer;
}
public async Task SayIntroText()
{
await SayAsync("Hello Master. Dieter is the best. Ha, ha, ha ha ha. I start now the Background Task.");
Logging.ToFile("----- SayIntroText() Done -----");
}
public async Task SayTimeEn()
{
var now = DateTime.Now;
var hour = now.Hour;
string timeOfDay;
if (hour <= 12)
{
timeOfDay = "morning";
}
else if (hour <= 17)
{
timeOfDay = "afternoon";
}
else
{
timeOfDay = "evening";
}
if (hour > 12)
{
hour -= 12;
}
if (now.Minute == 0)
{
await SayAsync($"Good {timeOfDay}. it's {hour} o'clock.");
}
else
{
await SayAsync($"Good {timeOfDay}. it's {hour} {now.Minute}.");
}
}
public async Task SayTimeDe()
{
var now = DateTime.Now;
var hour = now.Hour;
string timeOfDay;
if (hour <= 10)
{
timeOfDay = "Morgen";
}
else if (hour <= 13)
{
timeOfDay = "Tag";
}
else if (hour <= 17)
{
timeOfDay = "Nachmittag";
}
else
{
timeOfDay = "Abend";
}
if (hour > 120)
{
hour -= 12;
}
if (now.Minute == 0)
{
await SayAsync($"Guten {timeOfDay}. es ist {hour} Uhr.");
}
else
{
await SayAsync($"Guten {timeOfDay}. es ist {hour} Uhr und {now.Minute} Minuten.");
}
}
}
}
using System;
using System.Diagnostics;
using System.IO;
namespace TimeTalkerBackground
{
public sealed class Logging
{
public static void LogIni()
{
var day = DateTime.Now.ToString("yyyy-MMM-dd");
string logFilePath = Environment.ExpandEnvironmentVariables("D:") + @"\TimeTalkerLog"+day+".log";
FileStream hlogFile = new FileStream(logFilePath, FileMode.OpenOrCreate, FileAccess.Write);
Trace.Listeners.Add(new TextWriterTraceListener(hlogFile));
Trace.AutoFlush = true;
Trace.WriteLine("Logging started.", DateTime.Now.ToString("yyyy-MM-dd, HH:mm:ss. "));
Debug.WriteLine("Logging started", logFilePath);
}
public static void ToFile(string Message)
{
var now = DateTime.Now.ToString("K, yyyy-MM-dd, HH:mm:ss, ");
Trace.WriteLine(now + Message);
Debug.WriteLine(now + Message);
Trace.Flush();
}
}
}
Comments