Skip to content

Commit

Permalink
Model-Audio-Update
Browse files Browse the repository at this point in the history
  • Loading branch information
forki committed Nov 5, 2018
1 parent 5400dfd commit 3e1ea9a
Show file tree
Hide file tree
Showing 6 changed files with 487 additions and 524 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ deploy
/firmware
yarn-error.log
/src/PiServer/logs/clientlog.log
/src/PiServer/logs/
3 changes: 3 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Release Notes

## 0.14.24 - 2018-11-05
* Model-Audio-Update

## 0.14.24 - 2018-10-31
* TagHistory websocket

Expand Down
830 changes: 415 additions & 415 deletions paket.lock

Large diffs are not rendered by default.

73 changes: 41 additions & 32 deletions src/PiServer/Elmish.Audio.fs
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,6 @@ type Audio = {

let getMusikPlayerProcesses() = Process.GetProcessesByName("omxplayer.bin")

let play dispatch msg file volume =
let p = new System.Diagnostics.Process()
p.EnableRaisingEvents <- true
p.Exited.Add (fun _ -> dispatch msg)

let startInfo = System.Diagnostics.ProcessStartInfo()
startInfo.FileName <- "omxplayer"
let volume = int (System.Math.Round(2000. * System.Math.Log10 volume))
startInfo.Arguments <- sprintf "--vol %d " volume + file
p.StartInfo <- startInfo
p.Start() |> ignore

let setVolumeScript volume =
let volumeScript = "./volume.sh"
Expand All @@ -50,21 +39,7 @@ dbus-send --print-reply --session --reply-timeout=500 \
p.Start() |> ignore


let killMusikPlayer() = task {
for p in getMusikPlayerProcesses() do
if not p.HasExited then
try
let killP = new System.Diagnostics.Process()
let startInfo = System.Diagnostics.ProcessStartInfo()
startInfo.FileName <- "sudo"
startInfo.Arguments <- "kill -9 " + p.Id.ToString()
killP.StartInfo <- startInfo
let _ = killP.Start()

while not p.HasExited do
do! Task.Delay 10
with _ -> ()
}



[<RequireQualifiedAccess>]
Expand All @@ -73,28 +48,62 @@ module Program =
let withAudio stoppedMsg (program:Elmish.Program<_,_,_,_>) =
let mutable lastModel = None
let mutable lastView = None
let mutable activelyKilled = false

let play dispatch file volume =
let p = new System.Diagnostics.Process()
p.EnableRaisingEvents <- true
p.Exited.Add (fun _ ->
if not activelyKilled then
dispatch stoppedMsg)

let startInfo = System.Diagnostics.ProcessStartInfo()
startInfo.FileName <- "omxplayer"
let volume = int (System.Math.Round(2000. * System.Math.Log10 volume))
startInfo.Arguments <- sprintf "--vol %d " volume + file
p.StartInfo <- startInfo
activelyKilled <- false
p.Start() |> ignore

let killMusikPlayer() = task {
for p in getMusikPlayerProcesses() do
if not p.HasExited then
try
let killP = new System.Diagnostics.Process()
let startInfo = System.Diagnostics.ProcessStartInfo()
startInfo.FileName <- "sudo"
startInfo.Arguments <- "kill -9 " + p.Id.ToString()
killP.StartInfo <- startInfo
let _ = killP.Start()

while not p.HasExited do
do! Task.Delay 10
with _ -> ()
}

let setState model dispatch =
match lastModel with
| Some r when r = model -> ()
| _ ->
| _ ->
let (v:Audio) = program.view model dispatch
match lastView with
| Some r when r = v -> ()
| Some r ->
| Some r ->
if r.Url <> v.Url then
activelyKilled <- true
killMusikPlayer () |> Async.AwaitTask |> Async.RunSynchronously

if r.Url = v.Url && v.Url <> None && r.Volume <> v.Volume then
setVolumeScript v.Volume

match v.Url with
| Some url when v.Url <> r.Url ->
play dispatch stoppedMsg url v.Volume
play dispatch url v.Volume
| _ -> ()
| _ ->
match v.Url with
| Some url ->
play dispatch stoppedMsg url v.Volume
play dispatch url v.Volume
| _ -> ()

lastView <- Some v
Expand Down
84 changes: 27 additions & 57 deletions src/PiServer/PiServer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,12 @@ open Elmish.Audio

let firmwareTarget = System.IO.Path.GetFullPath "/home/pi/firmware"

let ofTask t p m1 m2 = Cmd.ofAsync (t >> Async.AwaitTask) p m1 m2

let runIn (timeSpan:TimeSpan) successMsg errorMsg =
let t() = task {
do! Task.Delay (int timeSpan.TotalMilliseconds)
return ()
}
ofTask t () (fun _ -> successMsg) errorMsg
Cmd.ofTask t () (fun _ -> successMsg) errorMsg


let log =
Expand All @@ -43,11 +41,6 @@ type PlayList = {
Position : int
}

[<RequireQualifiedAccess>]
type PlayListAction =
| Next
| Previous

type Model = {
PlayList : PlayList option
FirmwareUpdateInterval : TimeSpan
Expand All @@ -56,8 +49,6 @@ type Model = {
Volume : float
RFID : string option
YoutubeLinks : Map<string,string[]>
MediaPlayerProcess : Process option
NextPlayListAction : PlayListAction
NodeServices : INodeServices
}

Expand All @@ -75,16 +66,13 @@ type Msg =
| NextMediaFile
| PreviousMediaFile
| PlayerStopped of unit
| StartMediaPlayer
| Started of Process
| FinishPlaylist of unit
| Noop of unit
| DiscoverYoutube of string * bool
| NewYoutubeMediaFiles of string * string [] * bool
| Err of exn



let rfidLoop (dispatch,nodeServices:INodeServices) = task {
use _nextButton = new Button(Unosquare.RaspberryIO.Pi.Gpio.Pin07, fun () -> dispatch NextMediaFile)
use _previousButton = new Button(Unosquare.RaspberryIO.Pi.Gpio.Pin01, fun () -> dispatch PreviousMediaFile)
Expand Down Expand Up @@ -123,9 +111,7 @@ let init nodeServices : Model * Cmd<Msg> =
Volume = 0.5 // TODO: load from webserver
RFID = None
YoutubeLinks = Map.empty
NextPlayListAction = PlayListAction.Next
NodeServices = nodeServices
MediaPlayerProcess = None }, Cmd.ofMsg CheckFirmware
NodeServices = nodeServices }, Cmd.ofMsg CheckFirmware

let resolveRFID (model:Model,token:string) = task {
use webClient = new System.Net.WebClient()
Expand All @@ -138,8 +124,6 @@ let resolveRFID (model:Model,token:string) = task {
}




let mutable nextFirmwareCheck = DateTimeOffset.MinValue


Expand Down Expand Up @@ -278,7 +262,7 @@ let update (msg:Msg) (model:Model) =
{ model with Volume = vol }, Cmd.ofFunc setVolumeScript vol Noop Err

| NewRFID rfid ->
{ model with RFID = Some rfid }, ofTask resolveRFID (model,rfid) NewTag Err
{ model with RFID = Some rfid }, Cmd.ofTask resolveRFID (model,rfid) NewTag Err

| RFIDRemoved ->
{ model with RFID = None }, Cmd.ofMsg (FinishPlaylist())
Expand All @@ -289,48 +273,34 @@ let update (msg:Msg) (model:Model) =
| Play playList ->
let model = { model with PlayList = Some playList }
log.InfoFormat("Playing new PlayList: {0}: Files: {1}", playList.Uri, playList.MediaFiles.Length)
model, Cmd.ofMsg StartMediaPlayer
model, Cmd.none

| StartMediaPlayer ->
| PlayerStopped _ ->
model, Cmd.ofMsg NextMediaFile

| NextMediaFile ->
match model.PlayList with
| Some playList ->
if playList.Position < 0 || playList.Position >= playList.MediaFiles.Length then
log.InfoFormat("Playlist has only {0} elements. Can't play media file {1}.", playList.MediaFiles.Length , playList.Position + 1)
let newPlayList = { playList with Position = playList.Position + 1 }

if newPlayList.Position >= newPlayList.MediaFiles.Length then
model, Cmd.ofMsg (FinishPlaylist())
else
log.InfoFormat( "Playing audio file {0} / {1}", playList.Position + 1, playList.MediaFiles.Length)

model, Cmd.none
| None ->
log.Error "No playlist set"
{ model with PlayList = Some newPlayList }, Cmd.none
| _ ->
model, Cmd.none

| Started p ->
{ model with MediaPlayerProcess = Some p }, Cmd.none

| PlayerStopped _ ->
| PreviousMediaFile ->
match model.PlayList with
| Some playList ->
let model = { model with MediaPlayerProcess = None }
let newPlayList = { playList with Position = playList.Position - 1 }

let newPlayList =
match model.NextPlayListAction with
| PlayListAction.Next -> { playList with Position = playList.Position + 1 }
| PlayListAction.Previous -> { playList with Position = max 0 (playList.Position - 1) }

if newPlayList.Position >= newPlayList.MediaFiles.Length then
model, Cmd.ofMsg (FinishPlaylist())
if newPlayList.Position < 0 then
{ model with PlayList = Some { playList with Position = 0 } }, Cmd.none
else
{ model with PlayList = Some newPlayList }, Cmd.ofMsg StartMediaPlayer

{ model with PlayList = Some newPlayList }, Cmd.none
| _ ->
{ model with MediaPlayerProcess = None }, Cmd.none

| NextMediaFile ->
{ model with NextPlayListAction = PlayListAction.Next }, ofTask killMusikPlayer () Noop Err

| PreviousMediaFile ->
{ model with NextPlayListAction = PlayListAction.Previous }, ofTask killMusikPlayer () Noop Err
model, Cmd.none

| PlayYoutube youtubeURL ->
match model.YoutubeLinks.TryGetValue youtubeURL with
Expand All @@ -341,15 +311,15 @@ let update (msg:Msg) (model:Model) =
Position = 0
}

model, Cmd.batch [ofTask killMusikPlayer () FinishPlaylist Err; Cmd.ofMsg (Play playList)]
model, Cmd.ofMsg (Play playList)
| _ ->
model, Cmd.ofMsg (DiscoverYoutube (youtubeURL,true))

| FinishPlaylist _ ->
{ model with PlayList = None }, ofTask killMusikPlayer () PlayerStopped Err
{ model with PlayList = None }, Cmd.none

| DiscoverYoutube (youtubeURL,playAfterwards) ->
model, ofTask discoverYoutubeLink youtubeURL (fun (youtubeURL,files) -> NewYoutubeMediaFiles (youtubeURL,files,playAfterwards)) Err
model, Cmd.ofTask discoverYoutubeLink youtubeURL (fun (youtubeURL,files) -> NewYoutubeMediaFiles (youtubeURL,files,playAfterwards)) Err

| NewYoutubeMediaFiles (youtubeURL,files,playAfterwards) ->
let model = { model with YoutubeLinks = model.YoutubeLinks |> Map.add youtubeURL files }
Expand All @@ -359,7 +329,7 @@ let update (msg:Msg) (model:Model) =
model, Cmd.none

| CheckFirmware ->
model, ofTask checkFirmware model FirmwareUpToDate Err
model, Cmd.ofTask checkFirmware model FirmwareUpToDate Err

| Noop _ ->
model, Cmd.none
Expand All @@ -368,7 +338,7 @@ let update (msg:Msg) (model:Model) =
log.InfoFormat("Firmware {0} is uptodate.", ReleaseNotes.Version)
model,
Cmd.batch [
ofTask getStartupActions model ExecuteActions Err
Cmd.ofTask getStartupActions model ExecuteActions Err
[fun dispatch -> discoverAllYoutubeLinks (dispatch,model) |> Async.AwaitTask |> Async.StartImmediate ]
[fun dispatch -> rfidLoop (dispatch,model.NodeServices) |> Async.AwaitTask |> Async.StartImmediate ]
]
Expand All @@ -381,16 +351,16 @@ let update (msg:Msg) (model:Model) =
log.Warn "Unknown Tag"
model, Cmd.ofMsg (ExecuteActions rest)
| TagAction.StopMusik ->
model, Cmd.batch [ofTask killMusikPlayer () PlayerStopped Err; Cmd.ofMsg (ExecuteActions rest) ]
model, Cmd.batch [Cmd.ofMsg (FinishPlaylist()); Cmd.ofMsg (ExecuteActions rest) ]
| TagAction.PlayMusik url ->
let playList : PlayList = {
Uri = url
MediaFiles = [| url |]
Position = 0
}
model, Cmd.batch [ofTask killMusikPlayer () PlayerStopped Err; Cmd.ofMsg (Play playList); Cmd.ofMsg (ExecuteActions rest) ]
model, Cmd.batch [Cmd.ofMsg (Play playList); Cmd.ofMsg (ExecuteActions rest) ]
| TagAction.PlayYoutube youtubeURL ->
model, Cmd.batch [ofTask killMusikPlayer () PlayerStopped Err; Cmd.ofMsg (PlayYoutube youtubeURL); Cmd.ofMsg (ExecuteActions rest) ]
model, Cmd.batch [Cmd.ofMsg (PlayYoutube youtubeURL); Cmd.ofMsg (ExecuteActions rest) ]
| TagAction.PlayBlobMusik _ ->
log.Error "Blobs links need to be converted to direct links by the tag server"
model, Cmd.ofMsg (ExecuteActions rest)
Expand Down
20 changes: 0 additions & 20 deletions src/PiServer/read-tag.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
"use strict";
const mfrc522 = require("mfrc522-rpi");
//# Init WiringPi with SPI Channel 0
mfrc522.initWiringPi(0);

function decimalToHex(d) {
var padding = 2;
Expand All @@ -16,22 +13,5 @@ function decimalToHex(d) {
}

exports.read = function (callback, lastTag) {
mfrc522.reset();

let response = mfrc522.findCard();
if (!response.status) {
callback(null, "");
return;
}

//# Get the UID of the card
response = mfrc522.getUid();
if (!response.status) {
callback(null, "");
return;
}

const uid = response.data;
var data = uid.map(x => decimalToHex(x)).join('');
callback(null, data);
}

0 comments on commit 3e1ea9a

Please sign in to comment.