diff --git a/.DS_Store b/.DS_Store index 84e855c..fc0cdb8 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 2828560..f4e10d9 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -69,6 +69,7 @@ jobs: path: CHANGELOG.md - name: Upload Release id: create_release + if: steps.get_version.outputs.newVersion == 'true' uses: ncipollo/release-action@v1 with: allowUpdates: true @@ -85,148 +86,148 @@ jobs: echo "New Version: ${{ steps.get_version.outputs.newVersion }}" >> $GITHUB_STEP_SUMMARY echo "Channel: ${{ steps.get_version.outputs.channel }}" >> $GITHUB_STEP_SUMMARY echo "Type: ${{ steps.get_version.outputs.type }}" >> $GITHUB_STEP_SUMMARY - Build_Project: - runs-on: windows-2019 - needs: GetVersionNumber - if: needs.GetVersionNumber.outputs.newVersion == 'true' - env: - VERSION: ${{ needs.GetVersionNumber.outputs.version }} - steps: - # First we checkout the source repo - - name: Checkout repo - uses: actions/checkout@v4 - with: - fetch-depth: 0 - # Fetch all tags - - name: Fetch tags - run: git fetch --tags - # Generate the appropriate version number - # - name: Set Version Number - # shell: powershell - # run: | - # $version = ./.github/scripts/GenerateVersionNumber.ps1 - # echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - # Use the version number to set the version of the assemblies - - name: Update AssemblyInfo.cs - shell: powershell - run: | - Write-Output ${{ env.VERSION }} - ./.github/scripts/UpdateAssemblyVersion.ps1 ${{ env.VERSION }} - - name: restore Nuget Packages - run: nuget install .\packages.config -OutputDirectory .\packages -ExcludeVersion - # Login to Docker - - name: Login to Docker - uses: azure/docker-login@v1 - with: - username: ${{ secrets.DOCKERHUB_USER }} - password: ${{ secrets.DOCKERHUB_PASSWORD }} - # Build the solutions in the docker image - - name: Build Solution - shell: powershell - run: | - Invoke-Expression "docker run --rm --mount type=bind,source=""$($Env:GITHUB_WORKSPACE)"",target=""c:/project"" pepperdash/sspbuilder c:\cihelpers\vsidebuild.exe -Solution ""c:\project\$($Env:SOLUTION_PATH)$($Env:SOLUTION_FILE).sln"" -BuildSolutionConfiguration $($ENV:BUILD_TYPE)" - # Zip up the output files as needed - - name: Zip Build Output - shell: powershell - run: | - $destination = "$($Env:GITHUB_HOME)\output" - New-Item -ItemType Directory -Force -Path ($destination) - Get-ChildItem ($destination) - $exclusions = @("packages", "4-series") - # Trying to get any .json schema files (not currently working) - # Gets any files with the listed extensions. - Get-ChildItem -recurse -Path "$($Env:GITHUB_WORKSPACE)" -include "*.clz", "*.cpz", "*.cplz", "*.nuspec" | ForEach-Object { - $allowed = $true; - # Exclude any files in submodules - foreach ($exclude in $exclusions) { - if ((Split-Path $_.FullName -Parent).contains("$($exclude)")) { - $allowed = $false; - break; - } - } - if ($allowed) { - Write-Host "allowing $($_)" - $_; - } - } | Copy-Item -Destination ($destination) -Force - Write-Host "Getting matching files..." - # Get any files from the output folder that match the following extensions - Get-ChildItem -Path $destination | Where-Object {($_.Extension -eq ".clz") -or ($_.Extension -eq ".cpz" -or ($_.Extension -eq ".cplz"))} | ForEach-Object { - # Replace the extensions with dll and xml and create an array - $filenames = @($($_ -replace "cpz|clz|cplz", "dll"), $($_ -replace "cpz|clz|cplz", "xml")) - Write-Host "Filenames:" - Write-Host $filenames - if ($filenames.length -gt 0) { - # Attempt to get the files and return them to the output directory - Get-ChildItem -Recurse -Path "$($Env:GITHUB_WORKSPACE)" -include $filenames | Copy-Item -Destination ($destination) -Force - } - } - Get-ChildItem -Path $destination\*.cplz | Rename-Item -NewName { "$($_.BaseName)-$($Env:VERSION)$($_.Extension)" } - Compress-Archive -Path $destination -DestinationPath "$($Env:GITHUB_WORKSPACE)\$($Env:SOLUTION_FILE)-$($Env:VERSION).zip" -Force - Write-Host "Output Contents post Zip" - Get-ChildItem -Path $destination - # Write the version to a file to be consumed by the push jobs - - name: Write Version - run: Write-Output "$($Env:VERSION)" | Out-File -FilePath "$($Env:GITHUB_HOME)\output\version.txt" - # Upload output files - - name: Upload Build Output - uses: actions/upload-artifact@v3 - with: - name: ${{ env.SOLUTION_FILE}}-${{ env.VERSION}}.zip - path: ./${{ env.SOLUTION_FILE}}-${{ env.VERSION}}.zip - # Upload the Version file as an artifact - - name: Upload version.txt - uses: actions/upload-artifact@v3 - with: - name: Version - path: ${{env.GITHUB_HOME}}\output\version.txt - # Create the release on the source repo - - name: Get release notes - uses: actions/download-artifact@v3 - with: - name: change-log - - name: Upload Release - id: create_release - uses: ncipollo/release-action@v1 - with: - allowUpdates: true - artifacts: 'output\*.*(zip)' - prerelease: ${{ needs.GetVersionNumber.outputs.channel != '' }} - tag: ${{ needs.GetVersionNumber.outputs.tag }} - commit: ${{ github.sha }} - bodyFile: ./CHANGELOG.md - Push_Nuget_Package: - needs: [GetVersionNumber, Build_Project] - runs-on: windows-latest - env: - VERSION: ${{ needs.GetVersionNumber.outputs.version }} - steps: - - name: Download Build output - uses: actions/download-artifact@v3 - with: - name: ${{ env.SOLUTION_FILE}}-${{ env.VERSION }}.zip - path: ./ - - name: Unzip Build file - run: | - Get-ChildItem .\*.zip | Expand-Archive -DestinationPath .\ - Remove-Item -Path .\*.zip - - name: Copy Files to root & delete output directory - run: | - Remove-Item -Path .\* -Include @("*.cpz","*.md","*.cplz","*.json","*.dll","*.clz") - Get-ChildItem -Path .\output\* | Copy-Item -Destination .\ - Remove-Item -Path .\output -Recurse - - name: Add nuget.exe - uses: nuget/setup-nuget@v1 - - name: Add Github Packages source - run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username pepperdash -password ${{ secrets.GITHUB_TOKEN }} - - name: Create nuget package - run: nuget pack "./epi-essentials-mobile-control.nuspec" -version ${{ env.VERSION }} - - name: Publish nuget package to Github registry - run: nuget push **/*.nupkg -source github - - name: Add nuget.org API Key - run: nuget setApiKey ${{ secrets.NUGET_API_KEY }} - - name: Publish nuget package to nuget.org - run: nuget push **/*.nupkg -Source https://api.nuget.org/v3/index.json + # Build_Project: + # runs-on: windows-2019 + # needs: GetVersionNumber + # if: needs.GetVersionNumber.outputs.newVersion == 'true' + # env: + # VERSION: ${{ needs.GetVersionNumber.outputs.version }} + # steps: + # # First we checkout the source repo + # - name: Checkout repo + # uses: actions/checkout@v4 + # with: + # fetch-depth: 0 + # # Fetch all tags + # - name: Fetch tags + # run: git fetch --tags + # # Generate the appropriate version number + # # - name: Set Version Number + # # shell: powershell + # # run: | + # # $version = ./.github/scripts/GenerateVersionNumber.ps1 + # # echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + # # Use the version number to set the version of the assemblies + # - name: Update AssemblyInfo.cs + # shell: powershell + # run: | + # Write-Output ${{ env.VERSION }} + # ./.github/scripts/UpdateAssemblyVersion.ps1 ${{ env.VERSION }} + # - name: restore Nuget Packages + # run: nuget install .\packages.config -OutputDirectory .\packages -ExcludeVersion + # # Login to Docker + # - name: Login to Docker + # uses: azure/docker-login@v1 + # with: + # username: ${{ secrets.DOCKERHUB_USER }} + # password: ${{ secrets.DOCKERHUB_PASSWORD }} + # # Build the solutions in the docker image + # - name: Build Solution + # shell: powershell + # run: | + # Invoke-Expression "docker run --rm --mount type=bind,source=""$($Env:GITHUB_WORKSPACE)"",target=""c:/project"" pepperdash/sspbuilder c:\cihelpers\vsidebuild.exe -Solution ""c:\project\$($Env:SOLUTION_PATH)$($Env:SOLUTION_FILE).sln"" -BuildSolutionConfiguration $($ENV:BUILD_TYPE)" + # # Zip up the output files as needed + # - name: Zip Build Output + # shell: powershell + # run: | + # $destination = "$($Env:GITHUB_HOME)\output" + # New-Item -ItemType Directory -Force -Path ($destination) + # Get-ChildItem ($destination) + # $exclusions = @("packages", "4-series") + # # Trying to get any .json schema files (not currently working) + # # Gets any files with the listed extensions. + # Get-ChildItem -recurse -Path "$($Env:GITHUB_WORKSPACE)" -include "*.clz", "*.cpz", "*.cplz", "*.nuspec" | ForEach-Object { + # $allowed = $true; + # # Exclude any files in submodules + # foreach ($exclude in $exclusions) { + # if ((Split-Path $_.FullName -Parent).contains("$($exclude)")) { + # $allowed = $false; + # break; + # } + # } + # if ($allowed) { + # Write-Host "allowing $($_)" + # $_; + # } + # } | Copy-Item -Destination ($destination) -Force + # Write-Host "Getting matching files..." + # # Get any files from the output folder that match the following extensions + # Get-ChildItem -Path $destination | Where-Object {($_.Extension -eq ".clz") -or ($_.Extension -eq ".cpz" -or ($_.Extension -eq ".cplz"))} | ForEach-Object { + # # Replace the extensions with dll and xml and create an array + # $filenames = @($($_ -replace "cpz|clz|cplz", "dll"), $($_ -replace "cpz|clz|cplz", "xml")) + # Write-Host "Filenames:" + # Write-Host $filenames + # if ($filenames.length -gt 0) { + # # Attempt to get the files and return them to the output directory + # Get-ChildItem -Recurse -Path "$($Env:GITHUB_WORKSPACE)" -include $filenames | Copy-Item -Destination ($destination) -Force + # } + # } + # Get-ChildItem -Path $destination\*.cplz | Rename-Item -NewName { "$($_.BaseName)-$($Env:VERSION)$($_.Extension)" } + # Compress-Archive -Path $destination -DestinationPath "$($Env:GITHUB_WORKSPACE)\$($Env:SOLUTION_FILE)-$($Env:VERSION).zip" -Force + # Write-Host "Output Contents post Zip" + # Get-ChildItem -Path $destination + # # Write the version to a file to be consumed by the push jobs + # - name: Write Version + # run: Write-Output "$($Env:VERSION)" | Out-File -FilePath "$($Env:GITHUB_HOME)\output\version.txt" + # # Upload output files + # - name: Upload Build Output + # uses: actions/upload-artifact@v3 + # with: + # name: ${{ env.SOLUTION_FILE}}-${{ env.VERSION}}.zip + # path: ./${{ env.SOLUTION_FILE}}-${{ env.VERSION}}.zip + # # Upload the Version file as an artifact + # - name: Upload version.txt + # uses: actions/upload-artifact@v3 + # with: + # name: Version + # path: ${{env.GITHUB_HOME}}\output\version.txt + # # Create the release on the source repo + # - name: Get release notes + # uses: actions/download-artifact@v3 + # with: + # name: change-log + # - name: Upload Release + # id: create_release + # uses: ncipollo/release-action@v1 + # with: + # allowUpdates: true + # artifacts: 'output\*.*(zip)' + # prerelease: ${{ needs.GetVersionNumber.outputs.channel != '' }} + # tag: ${{ needs.GetVersionNumber.outputs.tag }} + # commit: ${{ github.sha }} + # bodyFile: ./CHANGELOG.md + # Push_Nuget_Package: + # needs: [GetVersionNumber, Build_Project] + # runs-on: windows-latest + # env: + # VERSION: ${{ needs.GetVersionNumber.outputs.version }} + # steps: + # - name: Download Build output + # uses: actions/download-artifact@v3 + # with: + # name: ${{ env.SOLUTION_FILE}}-${{ env.VERSION }}.zip + # path: ./ + # - name: Unzip Build file + # run: | + # Get-ChildItem .\*.zip | Expand-Archive -DestinationPath .\ + # Remove-Item -Path .\*.zip + # - name: Copy Files to root & delete output directory + # run: | + # Remove-Item -Path .\* -Include @("*.cpz","*.md","*.cplz","*.json","*.dll","*.clz") + # Get-ChildItem -Path .\output\* | Copy-Item -Destination .\ + # Remove-Item -Path .\output -Recurse + # - name: Add nuget.exe + # uses: nuget/setup-nuget@v1 + # - name: Add Github Packages source + # run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username pepperdash -password ${{ secrets.GITHUB_TOKEN }} + # - name: Create nuget package + # run: nuget pack "./epi-essentials-mobile-control.nuspec" -version ${{ env.VERSION }} + # - name: Publish nuget package to Github registry + # run: nuget push **/*.nupkg -source github + # - name: Add nuget.org API Key + # run: nuget setApiKey ${{ secrets.NUGET_API_KEY }} + # - name: Publish nuget package to nuget.org + # run: nuget push **/*.nupkg -Source https://api.nuget.org/v3/index.json Build_Project_4-Series: needs: GetVersionNumber if: needs.GetVersionNumber.outputs.newVersion == 'true' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index b7a2fa0..0000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,300 +0,0 @@ -name: Main Build using Docker - -on: - release: - types: - - created - branches: - - main -env: - # solution path doesn't need slashes unless there it is multiple folders deep - # solution name does not include extension. .sln is assumed - SOLUTION_PATH: 3-series\ - SOLUTION_FILE: epi-essentials-mobile-control - # Do not edit this, we're just creating it here - VERSION: 0.0.0-buildtype-buildnumber - # Defaults to debug for build type - BUILD_TYPE: Release - # Defaults to main as the release branch. Change as necessary - RELEASE_BRANCH: main -jobs: - Build_Project: - runs-on: windows-2019 - steps: - # First we checkout the source repo - - name: Checkout repo - uses: actions/checkout@v3 - with: - fetch-depth: 0 - # Generate the appropriate version number - - name: Set Version Number - shell: powershell - env: - TAG_NAME: ${{ github.event.release.tag_name }} - run: echo "VERSION=$($Env:TAG_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - # Use the version number to set the version of the assemblies - - name: Update AssemblyInfo.cs - shell: powershell - run: | - Write-Output ${{ env.VERSION }} - ./.github/scripts/UpdateAssemblyVersion.ps1 ${{ env.VERSION }} - - name: restore Nuget Packages - run: nuget install .\packages.config -OutputDirectory .\packages -ExcludeVersion - # Login to Docker - - name: Login to Docker - uses: azure/docker-login@v1 - with: - username: ${{ secrets.DOCKERHUB_USER }} - password: ${{ secrets.DOCKERHUB_PASSWORD }} - # Build the solutions in the docker image - - name: Build Solution - shell: powershell - run: | - Invoke-Expression "docker run --rm --mount type=bind,source=""$($Env:GITHUB_WORKSPACE)"",target=""c:/project"" pepperdash/sspbuilder c:\cihelpers\vsidebuild.exe -Solution ""c:\project\$($Env:SOLUTION_PATH)\$($Env:SOLUTION_FILE).sln"" -BuildSolutionConfiguration $($ENV:BUILD_TYPE)" - # Zip up the output files as needed - - name: Zip Build Output - shell: powershell - run: | - $destination = "$($Env:GITHUB_HOME)\output" - New-Item -ItemType Directory -Force -Path ($destination) - Get-ChildItem ($destination) - $exclusions = @("packages", "4-series") - # Trying to get any .json schema files (not currently working) - # Gets any files with the listed extensions. - Get-ChildItem -recurse -Path "$($Env:GITHUB_WORKSPACE)" -include "*.clz", "*.cpz", "*.cplz", "*.nuspec" | ForEach-Object { - $allowed = $true; - # Exclude any files in submodules - foreach ($exclude in $exclusions) { - if ((Split-Path $_.FullName -Parent).contains("$($exclude)")) { - $allowed = $false; - break; - } - } - if ($allowed) { - Write-Host "allowing $($_)" - $_; - } - } | Copy-Item -Destination ($destination) -Force - Write-Host "Getting matching files..." - # Get any files from the output folder that match the following extensions - Get-ChildItem -Path $destination | Where-Object {($_.Extension -eq ".clz") -or ($_.Extension -eq ".cpz" -or ($_.Extension -eq ".cplz"))} | ForEach-Object { - # Replace the extensions with dll and xml and create an array - $filenames = @($($_ -replace "cpz|clz|cplz", "dll"), $($_ -replace "cpz|clz|cplz", "xml")) - Write-Host "Filenames:" - Write-Host $filenames - if ($filenames.length -gt 0) { - # Attempt to get the files and return them to the output directory - Get-ChildItem -Recurse -Path "$($Env:GITHUB_WORKSPACE)" -include $filenames | Copy-Item -Destination ($destination) -Force - } - } - Get-ChildItem -Path $destination\*.cplz | Rename-Item -NewName { "$($_.BaseName)-$($Env:VERSION)$($_.Extension)" } - Compress-Archive -Path $destination -DestinationPath "$($Env:GITHUB_WORKSPACE)\$($Env:SOLUTION_FILE)-$($Env:VERSION).zip" -Force - Write-Host "Output Contents post Zip" - Get-ChildItem -Path $destination - # Write the version to a file to be consumed by the push jobs - - name: Write Version - run: Write-Output "$($Env:VERSION)" | Out-File -FilePath "$($Env:GITHUB_HOME)\output\version.txt" - - name: Upload Build Output - uses: actions/upload-artifact@v3 - with: - name: ${{ env.SOLUTION_FILE}}-${{ env.VERSION}}.zip - path: ./${{ env.SOLUTION_FILE}}-${{ env.VERSION}}.zip - # Upload the Version file as an artifact - - name: Upload version.txt - uses: actions/upload-artifact@v3 - with: - name: Version - path: ${{env.GITHUB_HOME}}\output\version.txt - # Upload the build package to the release - - name: Upload Release Package - id: upload_release - uses: actions/upload-release-asset@v1 - with: - upload_url: ${{ github.event.release.upload_url }} - asset_path: ./${{ env.SOLUTION_FILE}}-${{ env.VERSION}}.zip - asset_name: ${{ env.SOLUTION_FILE}}-${{ env.VERSION}}.zip - asset_content_type: application/zip - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - Push_Nuget_Package: - needs: Build_Project - runs-on: windows-latest - steps: - - name: Download Build Version Info - uses: actions/download-artifact@v3 - with: - name: Version - path: Version - - name: Set Version Number - shell: powershell - run: | - Get-ChildItem "./Version" - $version = Get-Content -Path ./Version/version.txt - Write-Host "Version: $version" - echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - Remove-Item -Path ./Version/version.txt - Remove-Item -Path ./Version - - name: Download Build output - uses: actions/download-artifact@v3 - with: - name: ${{ env.SOLUTION_FILE}}-${{ env.VERSION}}.zip - path: ./ - - name: Unzip Build file - run: | - Get-ChildItem .\*.zip | Expand-Archive -DestinationPath .\ - Remove-Item -Path .\*.zip - - name: Copy Files to root & delete output directory - run: | - Remove-Item -Path .\* -Include @("*.cpz","*.md","*.cplz","*.json","*.dll","*.clz") - Get-ChildItem -Path .\output\* | Copy-Item -Destination .\ - Remove-Item -Path .\output -Recurse - - name: Add nuget.exe - uses: nuget/setup-nuget@v1 - - name: Add Github Packages source - run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username Pepperdash -password ${{ secrets.GITHUB_TOKEN }} - - name: Create nuget package - run: nuget pack "./epi-essentials-mobile-control.nuspec" -version ${{ env.VERSION }} - - name: Publish nuget package to Github registry - run: nuget push **/*.nupkg -source github - - name: Add nuget.org API Key - run: nuget setApiKey ${{ secrets.NUGET_API_KEY }} - - name: Publish nuget package to nuget.org - run: nuget push **/*.nupkg -Source https://api.nuget.org/v3/index.json - Build_Project_4-Series: - runs-on: windows-latest - steps: - # First we checkout the source repo - - name: Checkout repo - uses: actions/checkout@v3 - with: - fetch-depth: 0 - # Generate the appropriate version number - - name: Set Version Number - shell: powershell - env: - TAG_NAME: ${{ github.event.release.tag_name }} - run: echo "VERSION=$($Env:TAG_NAME)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - # Use the version number to set the version of the assemblies - - name: Update AssemblyInfo.cs - shell: powershell - run: | - Write-Output ${{ env.VERSION }} - ./.github/scripts/UpdateAssemblyVersion.ps1 ${{ env.VERSION }} - - name: Setup MS-Build - uses: microsoft/setup-msbuild@v1 - - name: restore Nuget Packages - run: nuget restore ./4-series/$($Env:SOLUTION_FILE).sln - # Build the solutions in the docker image - - name: Build Solution - shell: powershell - run: | - msbuild ./4-series/$($Env:SOLUTION_FILE).sln /p:platform="Any CPU" /p:configuration="Release" - # Zip up the output files as needed - - name: Zip Build Output - shell: powershell - run: | - $destination = "$($Env:GITHUB_HOME)\output" - New-Item -ItemType Directory -Force -Path ($destination) - Get-ChildItem ($destination) - $exclusions = @("packages", "3-series") - # Trying to get any .json schema files (not currently working) - # Gets any files with the listed extensions. - Get-ChildItem -recurse -Path "$($Env:GITHUB_WORKSPACE)" -include "*.clz", "*.cpz", "*.cplz", "*.nuspec" | ForEach-Object { - $allowed = $true; - # Exclude any files in submodules - foreach ($exclude in $exclusions) { - if ((Split-Path $_.FullName -Parent).contains("$($exclude)")) { - $allowed = $false; - break; - } - } - if ($allowed) { - Write-Host "allowing $($_)" - $_; - } - } | Copy-Item -Destination ($destination) -Force - Write-Host "Getting matching files..." - # Get any files from the output folder that match the following extensions - Get-ChildItem -Path $destination | Where-Object {($_.Extension -eq ".clz") -or ($_.Extension -eq ".cpz" -or ($_.Extension -eq ".cplz"))} | ForEach-Object { - # Replace the extensions with dll and xml and create an array - $filenames = @($($_ -replace "cpz|clz|cplz", "dll"), $($_ -replace "cpz|clz|cplz", "xml")) - Write-Host "Filenames:" - Write-Host $filenames - if ($filenames.length -gt 0) { - # Attempt to get the files and return them to the output directory - Get-ChildItem -Recurse -Path "$($Env:GITHUB_WORKSPACE)" -include $filenames | Copy-Item -Destination ($destination) -Force - } - } - Get-ChildItem -Path $destination\*.cplz | Rename-Item -NewName { "$($_.BaseName)-4s-$($Env:VERSION)$($_.Extension)" } - Compress-Archive -Path $destination -DestinationPath "$($Env:GITHUB_WORKSPACE)\$($Env:SOLUTION_FILE)-4s-$($Env:VERSION).zip" -Force - Write-Host "Output Contents post Zip" - Get-ChildItem -Path $destination - # Write the version to a file to be consumed by the push jobs - - name: Write Version - run: Write-Output "$($Env:VERSION)" | Out-File -FilePath "$($Env:GITHUB_HOME)\output\version.txt" - - name: Upload Build Output - uses: actions/upload-artifact@v3 - with: - name: ${{ env.SOLUTION_FILE}}-4s-${{ env.VERSION}}.zip - path: ./${{ env.SOLUTION_FILE}}-4s-${{ env.VERSION}}.zip - # Upload the Version file as an artifact - - name: Upload version.txt - uses: actions/upload-artifact@v3 - with: - name: Version - path: ${{env.GITHUB_HOME}}\output\version.txt - # Upload the build package to the release - - name: Upload Release Package - id: upload_release - uses: actions/upload-release-asset@v1 - with: - upload_url: ${{ github.event.release.upload_url }} - asset_path: ./${{ env.SOLUTION_FILE}}-4s-${{ env.VERSION}}.zip - asset_name: ${{ env.SOLUTION_FILE}}-4s-${{ env.VERSION}}.zip - asset_content_type: application/zip - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - Push_Nuget_Package_4-Series: - needs: Build_Project_4-Series - runs-on: windows-latest - steps: - - name: Download Build Version Info - uses: actions/download-artifact@v3 - with: - name: Version - path: Version - - name: Set Version Number - shell: powershell - run: | - Get-ChildItem "./Version" - $version = Get-Content -Path ./Version/version.txt - Write-Host "Version: $version" - echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - Remove-Item -Path ./Version/version.txt - Remove-Item -Path ./Version - - name: Download Build output - uses: actions/download-artifact@v3 - with: - name: ${{ env.SOLUTION_FILE}}-4s-${{ env.VERSION}}.zip - path: ./ - - name: Unzip Build file - run: | - Get-ChildItem .\*.zip | Expand-Archive -DestinationPath .\ - Remove-Item -Path .\*.zip - - name: Copy Files to root & delete output directory - run: | - Remove-Item -Path .\* -Include @("*.cpz","*.md","*.cplz","*.json","*.dll","*.clz") - Get-ChildItem -Path .\output\* | Copy-Item -Destination .\ - Remove-Item -Path .\output -Recurse - - name: Add nuget.exe - uses: nuget/setup-nuget@v1 - - name: Add Github Packages source - run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username Pepperdash -password ${{ secrets.GITHUB_TOKEN }} - - name: Create nuget package - run: nuget pack "./epi-essentials-mobile-control.nuspec" -version ${{ env.VERSION }} - - name: Publish nuget package to Github registry - run: nuget push **/*.nupkg -source github - - name: Add nuget.org API Key - run: nuget setApiKey ${{ secrets.NUGET_API_KEY }} - - name: Publish nuget package to nuget.org - run: nuget push **/*.nupkg -Source https://api.nuget.org/v3/index.json diff --git a/.gitignore b/.gitignore index 9394468..4115880 100644 --- a/.gitignore +++ b/.gitignore @@ -362,3 +362,4 @@ MigrationBackup/ # Build Outputs output/ +/exampleConfigs/essentials-mc-test-configurationFile.json diff --git a/3-series/Messengers/AudioCodecBaseMessenger.cs b/3-series/Messengers/AudioCodecBaseMessenger.cs index b0fbbc9..0472241 100644 --- a/3-series/Messengers/AudioCodecBaseMessenger.cs +++ b/3-series/Messengers/AudioCodecBaseMessenger.cs @@ -1,9 +1,9 @@ -using System; -using System.Linq; -using PepperDash.Essentials.Devices.Common.Codec; -using PepperDash.Essentials.Devices.Common.AudioCodec; - +using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Devices.Common.AudioCodec; +using PepperDash.Essentials.Devices.Common.Codec; +using System; +using System.Linq; namespace PepperDash.Essentials.AppServer.Messengers { @@ -24,45 +24,62 @@ public class AudioCodecBaseMessenger : MessengerBase /// /// public AudioCodecBaseMessenger(string key, AudioCodecBase codec, string messagePath) - : base(key, messagePath) + : base(key, messagePath, codec) { - if (codec == null) - throw new ArgumentNullException("codec"); - - Codec = codec; - codec.CallStatusChange += codec_CallStatusChange; + Codec = codec ?? throw new ArgumentNullException("codec"); + codec.CallStatusChange += Codec_CallStatusChange; } #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif { - base.CustomRegisterWithAppServer(appServerController); + base.RegisterActions(); - appServerController.AddAction(MessagePath + "/fullStatus", new Action(SendAtcFullMessageObject)); - appServerController.AddAction(MessagePath + "/dial", new Action(s => Codec.Dial(s))); - appServerController.AddAction(MessagePath + "/endCallById", new Action(s => + AddAction("/fullStatus", (id, content) => SendAtcFullMessageObject()); + AddAction("/dial", (id, content) => { - var call = GetCallWithId(s); + var msg = content.ToObject>(); + + Codec.Dial(msg.Value); + }); + + AddAction("/endCallById", (id, content) => + { + var msg = content.ToObject>(); + + var call = GetCallWithId(msg.Value); if (call != null) Codec.EndCall(call); - })); - appServerController.AddAction(MessagePath + "/endAllCalls", new Action(Codec.EndAllCalls)); - appServerController.AddAction(MessagePath + "/dtmf", new Action(s => Codec.SendDtmf(s))); - appServerController.AddAction(MessagePath + "/rejectById", new Action(s => + }); + + AddAction("/endAllCalls", (id, content) => Codec.EndAllCalls()); + AddAction("/dtmf", (id, content) => { - var call = GetCallWithId(s); + var msg = content.ToObject>(); + + Codec.SendDtmf(msg.Value); + }); + + AddAction("/rejectById", (id, content) => + { + var msg = content.ToObject>(); + + var call = GetCallWithId(msg.Value); + if (call != null) Codec.RejectCall(call); - })); - appServerController.AddAction(MessagePath + "/acceptById", new Action(s => + }); + + AddAction("/acceptById", (id, content) => { - var call = GetCallWithId(s); + var msg = content.ToObject>(); + var call = GetCallWithId(msg.Value); if (call != null) Codec.AcceptCall(call); - })); + }); } /// @@ -75,7 +92,7 @@ private CodecActiveCallItem GetCallWithId(string id) return Codec.ActiveCalls.FirstOrDefault(c => c.Id == id); } - private void codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e) + private void Codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e) { SendAtcFullMessageObject(); } @@ -87,15 +104,17 @@ private void codec_CallStatusChange(object sender, CodecCallStatusItemChangeEven private void SendAtcFullMessageObject() { var info = Codec.CodecInfo; - PostStatusMessage(new - { - isInCall = Codec.IsInCall, - calls = Codec.ActiveCalls, - info = new + + PostStatusMessage(JToken.FromObject(new { - phoneNumber = info.PhoneNumber - } - }); + isInCall = Codec.IsInCall, + calls = Codec.ActiveCalls, + info = new + { + phoneNumber = info.PhoneNumber + } + }) + ); } } } \ No newline at end of file diff --git a/3-series/Messengers/CameraBaseMessenger.cs b/3-series/Messengers/CameraBaseMessenger.cs index 05c31a6..1a8f070 100644 --- a/3-series/Messengers/CameraBaseMessenger.cs +++ b/3-series/Messengers/CameraBaseMessenger.cs @@ -1,8 +1,9 @@ -using System; -using System.Collections.Generic; +using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core; -using PepperDash.Essentials.Devices.Common.Cameras; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Devices.Common.Cameras; +using System; +using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { @@ -20,143 +21,173 @@ public class CameraBaseMessenger : MessengerBase /// /// public CameraBaseMessenger(string key, CameraBase camera, string messagePath) - : base(key, messagePath) + : base(key, messagePath, camera) { - if (camera == null) - throw new ArgumentNullException("camera"); + Camera = camera ?? throw new ArgumentNullException("camera"); - Camera = camera; - var presetsCamera = Camera as IHasCameraPresets; - - if (presetsCamera != null) + if (Camera is IHasCameraPresets presetsCamera) { - presetsCamera.PresetsListHasChanged += presetsCamera_PresetsListHasChanged; + presetsCamera.PresetsListHasChanged += PresetsCamera_PresetsListHasChanged; } } - private void presetsCamera_PresetsListHasChanged(object sender, EventArgs e) + private void PresetsCamera_PresetsListHasChanged(object sender, EventArgs e) { - var presetsCamera = Camera as IHasCameraPresets; - var presetList = new List(); - if (presetsCamera != null) + if (Camera is IHasCameraPresets presetsCamera) presetList = presetsCamera.Presets; - PostStatusMessage(new - { - presets = presetList - }); + PostStatusMessage(JToken.FromObject(new + { + presets = presetList + }) + ); } #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif { - base.CustomRegisterWithAppServer(appServerController); + base.RegisterActions(); - appServerController.AddAction(MessagePath + "/fullStatus", new Action(SendCameraFullMessageObject)); + AddAction("/fullStatus", (id, content) => SendCameraFullMessageObject()); - var ptzCamera = Camera as IHasCameraPtzControl; - if (ptzCamera != null) + if (Camera is IHasCameraPtzControl ptzCamera) { // Need to evaluate how to pass through these P&H actions. Need a method that takes a bool maybe? - AppServerController.AddAction(MessagePath + "/cameraUp", new PressAndHoldAction(b => + AddAction("/cameraUp", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) + { ptzCamera.TiltUp(); - else - ptzCamera.TiltStop(); + return; + } + + ptzCamera.TiltStop(); })); - AppServerController.AddAction(MessagePath + "/cameraDown", new PressAndHoldAction(b => + AddAction("/cameraDown", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) + { ptzCamera.TiltDown(); - else - ptzCamera.TiltStop(); + return; + } + + ptzCamera.TiltStop(); })); - AppServerController.AddAction(MessagePath + "/cameraLeft", new PressAndHoldAction(b => + AddAction("/cameraLeft", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) + { ptzCamera.PanLeft(); - else - ptzCamera.PanStop(); + return; + } + + ptzCamera.PanStop(); })); - AppServerController.AddAction(MessagePath + "/cameraRight", new PressAndHoldAction(b => + AddAction("/cameraRight", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) + { ptzCamera.PanRight(); - else - ptzCamera.PanStop(); + return; + } + + ptzCamera.PanStop(); })); - AppServerController.AddAction(MessagePath + "/cameraZoomIn", new PressAndHoldAction(b => + AddAction("/cameraZoomIn", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) + { ptzCamera.ZoomIn(); - else - ptzCamera.ZoomStop(); + return; + } + + ptzCamera.ZoomStop(); })); - AppServerController.AddAction(MessagePath + "/cameraZoomOut", new PressAndHoldAction(b => + AddAction("/cameraZoomOut", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) + { ptzCamera.ZoomOut(); - else - ptzCamera.ZoomStop(); + return; + } + + ptzCamera.ZoomStop(); })); } if (Camera is IHasCameraAutoMode) { - appServerController.AddAction(MessagePath + "/cameraModeAuto", - new Action((Camera as IHasCameraAutoMode).CameraAutoModeOn)); - appServerController.AddAction(MessagePath + "/cameraModeManual", - new Action((Camera as IHasCameraAutoMode).CameraAutoModeOff)); + AddAction("/cameraModeAuto", (id, content) => (Camera as IHasCameraAutoMode).CameraAutoModeOn()); + + AddAction("/cameraModeManual", (id, content) => (Camera as IHasCameraAutoMode).CameraAutoModeOff()); + } if (Camera is IHasPowerControl) { - appServerController.AddAction(MessagePath + "/cameraModeOff", new Action((Camera as IHasPowerControl).PowerOff)); - appServerController.AddAction(MessagePath + "/cameraModeManual", new Action((Camera as IHasPowerControl).PowerOn)); + AddAction("/cameraModeOff", (id, content) => (Camera as IHasPowerControl).PowerOff()); + AddAction("/cameraModeManual", (id, content) => (Camera as IHasPowerControl).PowerOn()); } - var presetsCamera = Camera as IHasCameraPresets; - if (presetsCamera != null) + if (Camera is IHasCameraPresets presetsCamera) { for (int i = 1; i <= 6; i++) { var preset = i; - appServerController.AddAction(MessagePath + "/cameraPreset" + i, - new Action(p => presetsCamera.PresetSelect(preset))); + AddAction("/cameraPreset" + i, (id, content) => + { + var msg = content.ToObject>(); + + presetsCamera.PresetSelect(msg.Value); + }); + } } } + private void HandleCameraPressAndHold(JToken content, Action cameraAction) + { + var state = content.ToObject>(); + + var timerHandler = PressAndHoldHandler.GetPressAndHoldHandler(state.Value); + if (timerHandler == null) + { + return; + } + + timerHandler(state.Value, cameraAction); + + cameraAction(state.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase)); + } + /// /// Helper method to update the full status of the camera /// private void SendCameraFullMessageObject() { - var presetsCamera = Camera as IHasCameraPresets; - var presetList = new List(); - if (presetsCamera != null) + if (Camera is IHasCameraPresets presetsCamera) presetList = presetsCamera.Presets; - PostStatusMessage(new - { - cameraManualSupported = Camera is IHasCameraControls, - cameraAutoSupported = Camera is IHasCameraAutoMode, - cameraOffSupported = Camera is IHasCameraOff, - cameraMode = GetCameraMode(), - hasPresets = Camera is IHasCameraPresets, - presets = presetList - }); + PostStatusMessage(JToken.FromObject(new + { + cameraManualSupported = Camera is IHasCameraControls, + cameraAutoSupported = Camera is IHasCameraAutoMode, + cameraOffSupported = Camera is IHasCameraOff, + cameraMode = GetCameraMode(), + hasPresets = Camera is IHasCameraPresets, + presets = presetList + }) + ); } /// diff --git a/3-series/Messengers/CommMonitorMessenger.cs b/3-series/Messengers/CommMonitorMessenger.cs index 93cb411..6e6ded7 100644 --- a/3-series/Messengers/CommMonitorMessenger.cs +++ b/3-series/Messengers/CommMonitorMessenger.cs @@ -1,6 +1,8 @@ -using System; +using Newtonsoft.Json.Linq; +using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using System; namespace PepperDash.Essentials.AppServer.Messengers { @@ -12,12 +14,8 @@ public class CommMonitorMessenger : MessengerBase private readonly ICommunicationMonitor _monitor; - public CommMonitorMessenger(string key, string messagePath) : base(key, messagePath) - { - } - public CommMonitorMessenger(string key, string messagePath, ICommunicationMonitor monitor) - : this(key, messagePath) + : base(key, messagePath, monitor as Device) { _monitor = monitor; } @@ -26,15 +24,14 @@ private void SendStatus() { var messageObj = new { - commMonitor = new { + commMonitor = new + { online = _monitor.CommunicationMonitor.IsOnline, status = _monitor.CommunicationMonitor.Status.ToString() } }; - - - PostStatusMessage(messageObj); + AppSer(messageObj); } #region Overrides of MessengerBase @@ -45,23 +42,24 @@ protected override void CustomRegisterWithAppServer(IMobileControl3 appServerCon protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif { - appServerController.AddAction(MessagePath + "/fullStatus", new Action(SendStatus)); - + appServerController.AddAction(MessagePath + "/fullStatus", (id, content) => SendStatus()); + _monitor.CommunicationMonitor.IsOnlineFeedback.OutputChange += IsOnlineFeedbackOnOutputChange; _monitor.CommunicationMonitor.StatusChange += CommunicationMonitorOnStatusChange; } private void CommunicationMonitorOnStatusChange(object sender, MonitorStatusChangeEventArgs monitorStatusChangeEventArgs) { - var messageObj = new + var messageObj = new MobileControlMessage { - type = MessagePath + PollStatusPath, - content = new + Type = MessagePath + PollStatusPath, + Content = JToken.FromObject(new { - commMonitor = new { + commMonitor = new + { status = monitorStatusChangeEventArgs.Status.ToString() } - } + }) }; AppServerController.SendMessageObject(messageObj); @@ -69,15 +67,16 @@ private void CommunicationMonitorOnStatusChange(object sender, MonitorStatusChan private void IsOnlineFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) { - var messageObj = new + var messageObj = new MobileControlMessage { - type = MessagePath + OnlineStatusPath, - content = new + Type = MessagePath + OnlineStatusPath, + Content = JToken.FromObject(new { - commMonitor = new { + commMonitor = new + { online = feedbackEventArgs.BoolValue } - } + }) }; AppServerController.SendMessageObject(messageObj); diff --git a/3-series/Messengers/DevicePresetsModelMessenger.cs b/3-series/Messengers/DevicePresetsModelMessenger.cs index eff0a1b..8b1db5b 100644 --- a/3-series/Messengers/DevicePresetsModelMessenger.cs +++ b/3-series/Messengers/DevicePresetsModelMessenger.cs @@ -1,38 +1,28 @@ -using System; -using System.Collections.Generic; -using Newtonsoft.Json; +using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.Presets; +using System; +using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { - public class DevicePresetsModelMessenger:MessengerBase + public class DevicePresetsModelMessenger : MessengerBase { private readonly ITvPresetsProvider _presetsDevice; - public DevicePresetsModelMessenger(string key, string messagePath) : base(key, messagePath) - { - - } - public DevicePresetsModelMessenger(string key, string messagePath, ITvPresetsProvider presetsDevice) - : this(key, messagePath) + : base(key, messagePath, presetsDevice as Device) { _presetsDevice = presetsDevice; } - private void TvPresetsOnPresetChanged(ISetTopBoxNumericKeypad device, string channel) - { - throw new NotImplementedException(); - } - private void SendPresets() { - PostStatusMessage(new + PostStatusMessage(new PresetStateMessage { - favorites = _presetsDevice.TvPresets.PresetsList + Favorites = _presetsDevice.TvPresets.PresetsList }); } @@ -41,34 +31,42 @@ private void RecallPreset(ISetTopBoxNumericKeypad device, string channel) _presetsDevice.TvPresets.Dial(channel, device); } - private void SavePresets(List presets ) + private void SavePresets(List presets) { _presetsDevice.TvPresets.UpdatePresets(presets); } - + #region Overrides of MessengerBase #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif { - appServerController.AddAction(MessagePath + "/fullStatus", new Action(SendPresets)); - appServerController.AddAction(MessagePath + "/recall", new Action((p) => + AddAction("/fullStatus", (id, content) => SendPresets()); + + AddAction("/recall", (id, content) => { - var dev = DeviceManager.GetDeviceForKey(p.DeviceKey) as ISetTopBoxNumericKeypad; + var p = content.ToObject(); + - if (dev == null) + if (!(DeviceManager.GetDeviceForKey(p.DeviceKey) is ISetTopBoxNumericKeypad dev)) { Debug.Console(1, "Unable to find device with key {0}", p.DeviceKey); return; } RecallPreset(dev, p.Preset.Channel); - })); - appServerController.AddAction(MessagePath + "/save", new Action>(SavePresets)); + }); + + AddAction("/save", (id, content) => + { + var presets = content.ToObject>(); + + SavePresets(presets); + }); _presetsDevice.TvPresets.PresetsSaved += (p) => SendPresets(); } @@ -84,4 +82,10 @@ public class PresetChannelMessage [JsonProperty("deviceKey")] public string DeviceKey; } + + public class PresetStateMessage : DeviceStateMessageBase + { + [JsonProperty("favorites", NullValueHandling = NullValueHandling.Ignore)] + public List Favorites { get; set; } = new List(); + } } \ No newline at end of file diff --git a/3-series/Messengers/DeviceVolumeMessenger.cs b/3-series/Messengers/DeviceVolumeMessenger.cs index b558cff..44ef611 100644 --- a/3-series/Messengers/DeviceVolumeMessenger.cs +++ b/3-series/Messengers/DeviceVolumeMessenger.cs @@ -1,83 +1,157 @@ -using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Linq; +using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using static Crestron.SimplSharpPro.Lighting.ZumWired.ZumNetBridgeRoom.ZumWiredRoomInterface; namespace PepperDash.Essentials.AppServer.Messengers { - public class DeviceVolumeMessenger:MessengerBase + public class DeviceVolumeMessenger : MessengerBase { - private IBasicVolumeWithFeedback _device; - private string _deviceKey; + private readonly IBasicVolumeWithFeedback _localDevice; public DeviceVolumeMessenger(string key, string messagePath) : base(key, messagePath) { } - public DeviceVolumeMessenger(string key, string messagePath, string deviceKey, IBasicVolumeWithFeedback device) - : this(key, messagePath) + public DeviceVolumeMessenger(string key, string messagePath, IBasicVolumeWithFeedback device) + : base(key, messagePath, device as PepperDash.Core.Device) { - _device = device; - _deviceKey = deviceKey; + _localDevice = device; } private void SendStatus() { - var messageObj = new + var messageObj = new VolumeStateMessage { - volume = new + Volume = new Volume { - level = _device.VolumeLevelFeedback.IntValue, - muted = _device.MuteFeedback.BoolValue, + Level = _localDevice.VolumeLevelFeedback.IntValue, + Muted = _localDevice.MuteFeedback.BoolValue, + HasMute = true, // assume all devices have mute for now } }; + if (_localDevice is IBasicVolumeWithFeedbackAdvanced volumeAdvanced) + { + messageObj.Volume.RawValue = volumeAdvanced.RawVolumeLevel.ToString(); + messageObj.Volume.Units = volumeAdvanced.Units; + } + PostStatusMessage(messageObj); } #region Overrides of MessengerBase #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif { - appServerController.AddAction(MessagePath + "/fullStatus", new Action(SendStatus)); - appServerController.AddAction(MessagePath + "/level", new Action(_device.SetVolume)); + AddAction("/fullStatus", (id, content) => SendStatus()); - appServerController.AddAction(MessagePath + "/muteToggle", new Action( - (b) => { - if(b){ - _device.MuteToggle(); - }})); + AddAction("/level", (id, content) => + { + var volume = content.ToObject>(); - _device.MuteFeedback.OutputChange += (sender, args) => + _localDevice.SetVolume(volume.Value); + }); + + AddAction("/muteToggle", (id, content) => { - var messageObj = new - { - volume = new - { - muted = args.BoolValue - } - }; + var state = content.ToObject>(); + + if (!state.Value) return; + + _localDevice.MuteToggle(); + }); + + AddAction("/muteOn", (id, content) => + { + _localDevice.MuteOn(); + }); + + AddAction("/muteOff", (id, content) => + { + _localDevice.MuteOff(); + }); + + AddAction("/volumeUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => + { + _localDevice.VolumeUp(b); + })); + + - PostStatusMessage(messageObj); + AddAction("/volumeDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => _localDevice.VolumeDown(b))); + + _localDevice.MuteFeedback.OutputChange += (sender, args) => + { + PostStatusMessage(JToken.FromObject( + new + { + volume = new + { + muted = args.BoolValue + } + }) + ); }; - _device.VolumeLevelFeedback.OutputChange += (sender, args) => + _localDevice.VolumeLevelFeedback.OutputChange += (sender, args) => { - var messageObj = new + var rawValue = ""; + if (_localDevice is IBasicVolumeWithFeedbackAdvanced volumeAdvanced) + { + rawValue = volumeAdvanced.RawVolumeLevel.ToString(); + } + + var message = new { volume = new { - level = args.IntValue + level = args.IntValue, + rawValue } }; - PostStatusMessage(messageObj); + PostStatusMessage(JToken.FromObject(message)); }; + + } #endregion } + + public class VolumeStateMessage : DeviceStateMessageBase + { + [JsonProperty("volume", NullValueHandling = NullValueHandling.Ignore)] + public Volume Volume { get; set; } + } + + public class Volume + { + [JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)] + public int? Level { get; set; } + + [JsonProperty("hasMute", NullValueHandling = NullValueHandling.Ignore)] + public bool? HasMute { get; set; } + + [JsonProperty("muted", NullValueHandling = NullValueHandling.Ignore)] + public bool? Muted { get; set; } + + [JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)] + public string Label { get; set; } + + [JsonProperty("rawValue", NullValueHandling = NullValueHandling.Ignore)] + public string RawValue { get; set; } + + [JsonConverter(typeof(StringEnumConverter))] + [JsonProperty("units", NullValueHandling = NullValueHandling.Ignore)] + public eVolumeLevelUnits? Units { get; set; } + } } \ No newline at end of file diff --git a/3-series/Messengers/GenericMessenger.cs b/3-series/Messengers/GenericMessenger.cs index 51c4fcc..2a52db1 100644 --- a/3-series/Messengers/GenericMessenger.cs +++ b/3-series/Messengers/GenericMessenger.cs @@ -1,32 +1,24 @@ using PepperDash.Essentials.Core; -using System; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using System; namespace PepperDash.Essentials.AppServer.Messengers { public class GenericMessenger : MessengerBase { - private EssentialsDevice _device; - - public GenericMessenger(string key, EssentialsDevice device, string messagePath):base(key, messagePath, device) + public GenericMessenger(string key, EssentialsDevice device, string messagePath) : base(key, messagePath, device) { - if(device == null) - { - throw new ArgumentNullException("device"); - } - - _device = device; } #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif { - base.CustomRegisterWithAppServer(appServerController); + base.RegisterActions(); - appServerController.AddAction(string.Format("{0}/fullStatus", MessagePath), new Action(SendFullStatus)); + AddAction("/fullStatus", (id, content) => SendFullStatus()); } private void SendFullStatus() diff --git a/3-series/Messengers/IHasScheduleAwarenessMessenger.cs b/3-series/Messengers/IHasScheduleAwarenessMessenger.cs index 4d0a04e..056f2f2 100644 --- a/3-series/Messengers/IHasScheduleAwarenessMessenger.cs +++ b/3-series/Messengers/IHasScheduleAwarenessMessenger.cs @@ -1,10 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using PepperDash.Essentials.Devices.Common.Codec; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Devices.Common.Codec; +using System; +using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { @@ -13,41 +13,36 @@ public class IHasScheduleAwarenessMessenger : MessengerBase public IHasScheduleAwareness ScheduleSource { get; private set; } public IHasScheduleAwarenessMessenger(string key, IHasScheduleAwareness scheduleSource, string messagePath) - :base(key, messagePath) + : base(key, messagePath, scheduleSource as Device) { - if (scheduleSource == null) - { - throw new ArgumentNullException("scheduleSource"); - } - - ScheduleSource = scheduleSource; + ScheduleSource = scheduleSource ?? throw new ArgumentNullException("scheduleSource"); ScheduleSource.CodecSchedule.MeetingsListHasChanged += new EventHandler(CodecSchedule_MeetingsListHasChanged); ScheduleSource.CodecSchedule.MeetingEventChange += new EventHandler(CodecSchedule_MeetingEventChange); } #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif { - appServerController.AddAction(MessagePath + "/fullStatus", new Action(SendFullScheduleObject)); - + AddAction("/schedule/fullStatus", (id, content) => SendFullScheduleObject()); } - void CodecSchedule_MeetingEventChange(object sender, MeetingEventArgs e) + private void CodecSchedule_MeetingEventChange(object sender, MeetingEventArgs e) { - PostStatusMessage(new - { - meetingChange = new + PostStatusMessage(JToken.FromObject(new MeetingChangeMessage { - changeType = e.ChangeType.ToString(), - meeting = e.Meeting - } - }); + MeetingChange = new MeetingChange + { + ChangeType = e.ChangeType.ToString(), + Meeting = e.Meeting + } + }) + ); } - void CodecSchedule_MeetingsListHasChanged(object sender, EventArgs e) + private void CodecSchedule_MeetingsListHasChanged(object sender, EventArgs e) { SendFullScheduleObject(); } @@ -57,11 +52,35 @@ void CodecSchedule_MeetingsListHasChanged(object sender, EventArgs e) /// private void SendFullScheduleObject() { - PostStatusMessage(new - { - meetings = ScheduleSource.CodecSchedule.Meetings, - meetingWarningMinutes = ScheduleSource.CodecSchedule.MeetingWarningMinutes - }); + PostStatusMessage(new FullScheduleMessage + { + Meetings = ScheduleSource.CodecSchedule.Meetings, + MeetingWarningMinutes = ScheduleSource.CodecSchedule.MeetingWarningMinutes + }); } } + + public class FullScheduleMessage : DeviceStateMessageBase + { + [JsonProperty("meetings", NullValueHandling = NullValueHandling.Ignore)] + public List Meetings { get; set; } + + [JsonProperty("meetingWarningMinutes", NullValueHandling = NullValueHandling.Ignore)] + public int MeetingWarningMinutes { get; set; } + } + + public class MeetingChangeMessage + { + [JsonProperty("meetingChange", NullValueHandling = NullValueHandling.Ignore)] + public MeetingChange MeetingChange { get; set; } + } + + public class MeetingChange + { + [JsonProperty("changeType", NullValueHandling = NullValueHandling.Ignore)] + public string ChangeType { get; set; } + + [JsonProperty("meeting", NullValueHandling = NullValueHandling.Ignore)] + public Meeting Meeting { get; set; } + } } \ No newline at end of file diff --git a/3-series/Messengers/IRunRouteActionMessenger.cs b/3-series/Messengers/IRunRouteActionMessenger.cs index dbb31b0..88d0a5b 100644 --- a/3-series/Messengers/IRunRouteActionMessenger.cs +++ b/3-series/Messengers/IRunRouteActionMessenger.cs @@ -1,7 +1,8 @@ -using System; -using PepperDash.Essentials.Core; +using Newtonsoft.Json; using PepperDash.Core; +using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using System; namespace PepperDash.Essentials.AppServer.Messengers @@ -14,40 +15,36 @@ public class RunRouteActionMessenger : MessengerBase public IRunRouteAction RoutingDevice { get; private set; } public RunRouteActionMessenger(string key, IRunRouteAction routingDevice, string messagePath) - : base(key, messagePath) + : base(key, messagePath, routingDevice as Device) { - if (routingDevice == null) - throw new ArgumentNullException("routingDevice"); - - RoutingDevice = routingDevice; + RoutingDevice = routingDevice ?? throw new ArgumentNullException("routingDevice"); - var routingSink = RoutingDevice as IRoutingSink; - if (routingSink != null) + if (RoutingDevice is IRoutingSink routingSink) { - routingSink.CurrentSourceChange += routingSink_CurrentSourceChange; + routingSink.CurrentSourceChange += RoutingSink_CurrentSourceChange; } } - private void routingSink_CurrentSourceChange(SourceListItem info, ChangeType type) + private void RoutingSink_CurrentSourceChange(SourceListItem info, ChangeType type) { SendRoutingFullMessageObject(); } #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif { - appServerController.AddAction(MessagePath + "/fullStatus", new Action(SendRoutingFullMessageObject)); + AddAction("/fullStatus", (id, content) => SendRoutingFullMessageObject()); - appServerController.AddAction(MessagePath + "/source", - new Action(c => + AddAction("/source", (id, content) => { + var c = content.ToObject(); // assume no sourceListKey var sourceListKey = string.Empty; - + if (!string.IsNullOrEmpty(c.SourceListKey)) { // Check for source list in content of message @@ -55,11 +52,10 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle sourceListKey = c.SourceListKey; } - RoutingDevice.RunRouteAction(c.SourceListItem,sourceListKey); - })); + RoutingDevice.RunRouteAction(c.SourceListItemKey, sourceListKey); + }); - var sinkDevice = RoutingDevice as IRoutingSink; - if (sinkDevice != null) + if (RoutingDevice is IRoutingSink sinkDevice) { sinkDevice.CurrentSourceChange += (o, a) => SendRoutingFullMessageObject(); } @@ -70,20 +66,24 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle /// private void SendRoutingFullMessageObject() { - var sinkDevice = RoutingDevice as IRoutingSink; - - if (sinkDevice != null) + if (RoutingDevice is IRoutingSink sinkDevice) { var sourceKey = sinkDevice.CurrentSourceInfoKey; if (string.IsNullOrEmpty(sourceKey)) sourceKey = "none"; - PostStatusMessage(new + PostStatusMessage(new RoutingStateMessage { - selectedSourceKey = sourceKey + SelectedSourceKey = sourceKey }); } } } + + public class RoutingStateMessage : DeviceStateMessageBase + { + [JsonProperty("selectedSourceKey")] + public string SelectedSourceKey { get; set; } + } } \ No newline at end of file diff --git a/3-series/Messengers/LightingBaseMessenger.cs b/3-series/Messengers/LightingBaseMessenger.cs index 145b9a1..4058c3a 100644 --- a/3-series/Messengers/LightingBaseMessenger.cs +++ b/3-series/Messengers/LightingBaseMessenger.cs @@ -1,55 +1,50 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - +using Newtonsoft.Json; using PepperDash.Core; -using PepperDash.Essentials.Core.Lighting; - -using Newtonsoft.Json; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Core.Lighting; +using System; +using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { - public class LightingBaseMessenger : MessengerBase + public class ILightingScenesMessenger : MessengerBase { - protected LightingBase Device { get; private set; } + protected ILightingScenes Device { get; private set; } - public LightingBaseMessenger(string key, LightingBase device, string messagePath) - : base(key, messagePath, device) + public ILightingScenesMessenger(string key, ILightingScenes device, string messagePath) + : base(key, messagePath, device as Device) { - if (device == null) - { - throw new ArgumentNullException("device"); - } - - Device = device; + Device = device ?? throw new ArgumentNullException("device"); Device.LightingSceneChange += new EventHandler(LightingDevice_LightingSceneChange); - + } - void LightingDevice_LightingSceneChange(object sender, LightingSceneChangeEventArgs e) + private void LightingDevice_LightingSceneChange(object sender, LightingSceneChangeEventArgs e) { - var state = new LightingBaseStateMessage(); - - state.CurrentLightingScene = e.CurrentLightingScene; + var state = new LightingBaseStateMessage + { + CurrentLightingScene = e.CurrentLightingScene + }; PostStatusMessage(state); } #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif { - base.CustomRegisterWithAppServer(appServerController); + base.RegisterActions(); - appServerController.AddAction(string.Format("{0}/fullStatus", MessagePath), new Action(SendFullStatus)); + AddAction("/fullStatus", (id, content) => SendFullStatus()); - appServerController.AddAction(string.Format("{0}/selectScene", MessagePath), new Action((s) => Device.SelectScene(s))); + AddAction("/selectScene", (id, content) => + { + var s = content.ToObject(); + Device.SelectScene(s); + }); } @@ -57,10 +52,11 @@ private void SendFullStatus() { Debug.Console(2, "LightingBaseMessenger GetFullStatus"); - var state = new LightingBaseStateMessage(); - - state.Scenes = Device.LightingScenes; - state.CurrentLightingScene = Device.CurrentLightingScene; + var state = new LightingBaseStateMessage + { + Scenes = Device.LightingScenes, + CurrentLightingScene = Device.CurrentLightingScene + }; PostStatusMessage(state); } diff --git a/3-series/Messengers/MessengerBase.cs b/3-series/Messengers/MessengerBase.cs index f1cf26a..75206e3 100644 --- a/3-series/Messengers/MessengerBase.cs +++ b/3-series/Messengers/MessengerBase.cs @@ -1,11 +1,12 @@ -using System; -using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; - -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using System; +using System.Collections.Generic; +using System.Linq; namespace PepperDash.Essentials.AppServer.Messengers { @@ -18,15 +19,19 @@ public abstract class MessengerBase : EssentialsDevice, IMobileControlMessenger public abstract class MessengerBase: EssentialsDevice #endif { - private Device _device; + protected IKeyName _device; + + private readonly List _deviceInterfaces; - private List _deviceIntefaces; + private readonly Dictionary> _actions = new Dictionary>(); + + public string DeviceKey => _device?.Key ?? ""; /// /// /// #if SERIES4 - public IMobileControl3 AppServerController { get; private set; } + public IMobileControl AppServerController { get; private set; } #else public MobileControlSystemController AppServerController { get; private set; } #endif @@ -49,30 +54,22 @@ protected MessengerBase(string key, string messagePath) MessagePath = messagePath; } - protected MessengerBase(string key, string messagePath, Device device) + protected MessengerBase(string key, string messagePath, IKeyName device) : this(key, messagePath) { _device = device; - _deviceIntefaces = GetInterfaces(_device); + _deviceInterfaces = GetInterfaces(_device as Device); } /// - /// Gets the intefaces implmented on the device + /// Gets the interfaces implmented on the device /// /// /// private List GetInterfaces(Device device) { - var interfaceTypes = device.GetType().GetInterfaces(); - - List interfaces = new List(); - - foreach (var i in interfaceTypes) - { - interfaces.Add(i.Name); - } - return interfaces; + return device?.GetType().GetInterfaces().Select((i) => i.Name).ToList() ?? new List(); } /// @@ -80,81 +77,68 @@ private List GetInterfaces(Device device) /// /// #if SERIES4 - public void RegisterWithAppServer(IMobileControl3 appServerController) + public void RegisterWithAppServer(IMobileControl appServerController) #else public void RegisterWithAppServer(MobileControlSystemController appServerController) #endif { - if (appServerController == null) - throw new ArgumentNullException("appServerController"); + AppServerController = appServerController ?? throw new ArgumentNullException("appServerController"); - AppServerController = appServerController; - CustomRegisterWithAppServer(AppServerController); + AppServerController.AddAction(this, HandleMessage); + + RegisterActions(); } - /// - /// Implemented in extending classes. Wire up API calls and feedback here - /// - /// -#if SERIES4 - protected virtual void CustomRegisterWithAppServer(IMobileControl3 appServerController) -#else - protected virtual void CustomRegisterWithAppServer(MobileControlSystemController appServerController) -#endif + private void HandleMessage(string path, string id, JToken content) { - var commMonitor = _device as ICommunicationMonitor; - - if (commMonitor != null) - { - //Debug.Console(2, this, "Subscribing to CommunicationMonitor.StatusChange on: ", _device.Key); - commMonitor.CommunicationMonitor.StatusChange += CommunicationMonitor_StatusChange; + // replace base path with empty string. Should leave something like /fullStatus + var route = path.Replace(MessagePath, string.Empty); - GetCommunicationMonitorState(); + if(!_actions.TryGetValue(route, out var action)) { + Debug.Console(1, this, $"No action found for path {path}"); + return; } + + action(id, content); } - private void CommunicationMonitor_StatusChange(object sender, MonitorStatusChangeEventArgs e) + protected void AddAction(string path, Action action) { - var message = new DeviceStateMessageBase(); - message.CommMonitor = GetCommunicationMonitorState(); + if (_actions.ContainsKey(path)) + { + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Messenger {Key} already has action registered at {path}", this); + return; + } + _actions.Add(path, action); + } - PostStatusMessage(message); + public List GetActionPaths() + { + return _actions.Keys.ToList(); } - protected CommunicationMonitorState GetCommunicationMonitorState() + protected void RemoveAction(string path) { - var commMonitor = _device as ICommunicationMonitor; - if (commMonitor != null) + if (!_actions.ContainsKey(path)) { - var state = new CommunicationMonitorState(); - state.IsOnline = commMonitor.CommunicationMonitor.IsOnline; - state.Status = commMonitor.CommunicationMonitor.Status; - //Debug.Console(2, this, "******************GetCommunitcationMonitorState() IsOnline: {0} Status: {1}", state.IsOnline, state.Status); - return state; - } - else - { - //Debug.Console(2, this, "******************Device does not implement ICommunicationMonitor"); - return null; + return; } + + _actions.Remove(path); } /// - /// Helper for posting status message + /// Implemented in extending classes. Wire up API calls and feedback here /// - /// The contents of the content object - [Obsolete("Will be removed in next major release, please use overload as substitute")] - protected void PostStatusMessage(object contentObject) + /// +#if SERIES4 + protected virtual void RegisterActions() +#else + protected virtual void CustomRegisterWithAppServer(MobileControlSystemController appServerController) +#endif { - if (AppServerController != null) - { - AppServerController.SendMessageObject(new - { - type = MessagePath, - content = contentObject - }); - } + } /// @@ -162,67 +146,74 @@ protected void PostStatusMessage(object contentObject) /// /// /// - protected void PostStatusMessage(DeviceStateMessageBase message) + protected void PostStatusMessage(DeviceStateMessageBase message, string clientId = null) { - if (AppServerController != null) - { - message.SetInterfaces(_deviceIntefaces); + message.SetInterfaces(_deviceInterfaces); - message.Key = _device.Key; + message.Key = _device.Key; - message.Name = _device.Name; + message.Name = _device.Name; - AppServerController.SendMessageObject(new - { - type = MessagePath, - content = message, - }); - } + PostStatusMessage(JToken.FromObject(message),MessagePath, clientId); } -#if SERIES4 - protected void PostStatusMessage(IMobileControlResponseMessage message) - +#if SERIES4 + protected void PostStatusMessage(string type, DeviceStateMessageBase deviceState, string clientId = null) { - if (AppServerController == null) - { - return; - } + //Debug.Console(2, this, "*********************Setting DeviceStateMessageProperties on MobileControlResponseMessage"); + deviceState.SetInterfaces(_deviceInterfaces); - var deviceState = message.Content as DeviceStateMessageBase; - if (deviceState != null) - { - //Debug.Console(2, this, "*********************Setting DeviceStateMessageProperties on MobileControlResponseMessage"); - deviceState.SetInterfaces(_deviceIntefaces); + deviceState.Key = _device.Key; - deviceState.Key = _device.Key; + deviceState.Name = _device.Name; - deviceState.Name = _device.Name; - } - //else - //{ - // Debug.Console(2, this, "*********************Content is not DeviceStateMessageBase"); - //} + deviceState.MessageBasePath = MessagePath; - AppServerController.SendMessageObject(message); + PostStatusMessage(JToken.FromObject(deviceState), type, clientId); } #endif + protected void PostStatusMessage(JToken content, string type = "", string clientId = null) + { + AppServerController?.SendMessageObject(new MobileControlMessage { Type = !string.IsNullOrEmpty(type) ? type : MessagePath, ClientId = clientId, Content = content }); + } protected void PostEventMessage(DeviceEventMessageBase message) { - if (AppServerController != null) + message.Key = _device.Key; + + message.Name = _device.Name; + + AppServerController?.SendMessageObject(new MobileControlMessage { - message.Key = _device.Key; + Type = $"/event{MessagePath}/{message.EventType}", + Content = JToken.FromObject(message), + }); + } - message.Name = _device.Name; + protected void PostEventMessage(DeviceEventMessageBase message, string eventType) + { + message.Key = _device.Key; + + message.Name = _device.Name; - AppServerController.SendMessageObject(new - { - type = MessagePath, - content = message, - }); - } + message.EventType = eventType; + + AppServerController?.SendMessageObject(new MobileControlMessage + { + Type = $"/event{MessagePath}/{eventType}", + Content = JToken.FromObject(message), + }); + } + + protected void PostEventMessage(string eventType) + { + AppServerController?.SendMessageObject(new MobileControlMessage + { + Type = $"/event{MessagePath}/{eventType}", + Content = JToken.FromObject(new { }), + }); } + } public abstract class DeviceMessageBase @@ -243,26 +234,17 @@ public abstract class DeviceMessageBase /// The type of the message class /// [JsonProperty("messageType")] - public string MessageType - { - get - { - return this.GetType().Name; - } - } + public string MessageType => GetType().Name; + + [JsonProperty("messageBasePath")] + public string MessageBasePath { get; set; } } - + /// /// Base class for state messages that includes the type of message and the implmented interfaces /// public class DeviceStateMessageBase : DeviceMessageBase { - /// - /// For devices that implement ICommunicationMonitor, reports the online status of the device - /// - [JsonProperty("commMonitor", NullValueHandling = NullValueHandling.Ignore)] - public CommunicationMonitorState CommMonitor { get; set; } - /// /// The interfaces implmented by the device sending the messsage /// @@ -287,23 +269,4 @@ public abstract class DeviceEventMessageBase : DeviceMessageBase public string EventType { get; set; } } - /// - /// Represents the state of the communication monitor - /// - public class CommunicationMonitorState - { - /// - /// For devices that implement ICommunicationMonitor, reports the online status of the device - /// - [JsonProperty("isOnline", NullValueHandling = NullValueHandling.Ignore)] - public bool? IsOnline { get; set; } - - /// - /// For devices that implement ICommunicationMonitor, reports the online status of the device - /// - [JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(StringEnumConverter))] - public MonitorStatus Status { get; set; } - - } } \ No newline at end of file diff --git a/3-series/Messengers/RoomEventScheduleMessenger.cs b/3-series/Messengers/RoomEventScheduleMessenger.cs index c7f3c24..a32eb5a 100644 --- a/3-series/Messengers/RoomEventScheduleMessenger.cs +++ b/3-series/Messengers/RoomEventScheduleMessenger.cs @@ -1,20 +1,20 @@ -using System; -using System.Collections.Generic; +using Newtonsoft.Json; using PepperDash.Core; -using PepperDash.Essentials.Room.Config; +using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Room.Config; +using System; +using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { - public class RoomEventScheduleMessenger:MessengerBase + public class RoomEventScheduleMessenger : MessengerBase { - private readonly EssentialsTechRoom _room; - public RoomEventScheduleMessenger(string key, string messagePath) : base(key, messagePath) - { - } + private readonly IRoomEventSchedule _room; - public RoomEventScheduleMessenger(string key, string messagePath, EssentialsTechRoom room) - : this(key, messagePath) + + public RoomEventScheduleMessenger(string key, string messagePath, IRoomEventSchedule room) + : base(key, messagePath, room as Device) { _room = room; } @@ -22,20 +22,20 @@ public RoomEventScheduleMessenger(string key, string messagePath, EssentialsTech #region Overrides of MessengerBase #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif { - appServerController.AddAction(MessagePath + "/save", new Action>(SaveScheduledEvents)); - appServerController.AddAction(MessagePath + "/fullStatus", new Action(() => + AddAction("/saveScheduledEvents", (id, content) => SaveScheduledEvents(content.ToObject>())); + AddAction("/status", (id, content) => { var events = _room.GetScheduledEvents(); SendFullStatus(events); - })); + }); - _room.ScheduledEventsChanged += (sender, args) => SendFullStatus(args.ScheduledEvents); + _room.ScheduledEventsChanged += (sender, args) => SendFullStatus(args.ScheduledEvents); } #endregion @@ -60,15 +60,21 @@ private void SaveScheduledEvent(ScheduledEventConfig eventConfig) } } - private void SendFullStatus(List events) + private void SendFullStatus(List events) { - var message = new - { - scheduleEvents = events, - }; + var message = new RoomEventScheduleStateMessage + { + ScheduleEvents = events, + }; - PostStatusMessage(message); + PostStatusMessage(message); } } + + public class RoomEventScheduleStateMessage : DeviceStateMessageBase + { + [JsonProperty("scheduleEvents")] + public List ScheduleEvents { get; set; } + } } \ No newline at end of file diff --git a/3-series/Messengers/SIMPLAtcMessenger.cs b/3-series/Messengers/SIMPLAtcMessenger.cs index af85b45..3f2ab69 100644 --- a/3-series/Messengers/SIMPLAtcMessenger.cs +++ b/3-series/Messengers/SIMPLAtcMessenger.cs @@ -1,13 +1,14 @@ -using System; -using System.Collections.Generic; -using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.DeviceSupport; +using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core; -using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Devices.Common.Codec; +using System; +using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { -// ReSharper disable once InconsistentNaming + // ReSharper disable once InconsistentNaming public class SIMPLAtcMessenger : MessengerBase { private readonly BasicTriList _eisc; @@ -34,7 +35,7 @@ public SIMPLAtcMessenger(string key, BasicTriList eisc, string messagePath) JoinMap = new SIMPLAtcJoinMap(201); - _currentCallItem = new CodecActiveCallItem {Type = eCodecCallType.Audio, Id = "-audio-"}; + _currentCallItem = new CodecActiveCallItem { Type = eCodecCallType.Audio, Id = "-audio-" }; } /// @@ -42,13 +43,14 @@ public SIMPLAtcMessenger(string key, BasicTriList eisc, string messagePath) /// private void SendFullStatus() { - PostStatusMessage(new - { - calls = GetCurrentCallList(), - currentCallString = _eisc.GetString(JoinMap.CurrentCallName.JoinNumber), - currentDialString = _eisc.GetString(JoinMap.CurrentDialString.JoinNumber), - isInCall = _eisc.GetString(JoinMap.HookState.JoinNumber) == "Connected" - }); + PostStatusMessage(JToken.FromObject(new + { + calls = GetCurrentCallList(), + currentCallString = _eisc.GetString(JoinMap.CurrentCallName.JoinNumber), + currentDialString = _eisc.GetString(JoinMap.CurrentDialString.JoinNumber), + isInCall = _eisc.GetString(JoinMap.HookState.JoinNumber) == "Connected" + }) + ); } /// @@ -56,7 +58,7 @@ private void SendFullStatus() /// /// #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif @@ -65,7 +67,7 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle _eisc.SetStringSigAction(JoinMap.HookState.JoinNumber, s => { - _currentCallItem.Status = (eCodecCallStatus) Enum.Parse(typeof (eCodecCallStatus), s, true); + _currentCallItem.Status = (eCodecCallStatus)Enum.Parse(typeof(eCodecCallStatus), s, true); //GetCurrentCallList(); SendFullStatus(); }); @@ -84,7 +86,7 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle _eisc.SetStringSigAction(JoinMap.CallDirection.JoinNumber, s => { - _currentCallItem.Direction = (eCodecCallDirection) Enum.Parse(typeof (eCodecCallDirection), s, true); + _currentCallItem.Direction = (eCodecCallDirection)Enum.Parse(typeof(eCodecCallDirection), s, true); SendCallsList(); }); @@ -93,8 +95,8 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle // AppServerController.AddAction(MessagePath + s, new PressAndHoldAction(b => _eisc.SetBool(u, b))); // Add straight pulse calls - Action addAction = (s, u) => - AppServerController.AddAction(MessagePath + s, new Action(() => _eisc.PulseBool(u, 100))); + void addAction(string s, uint u) => + AddAction(s, (id, content) => _eisc.PulseBool(u, 100)); addAction("/endCallById", JoinMap.EndCall.JoinNumber); addAction("/endAllCalls", JoinMap.EndCall.JoinNumber); addAction("/acceptById", JoinMap.IncomingAnswer.JoinNumber); @@ -111,14 +113,20 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle } // Get status - AppServerController.AddAction(MessagePath + "/fullStatus", new Action(SendFullStatus)); + AddAction("/fullStatus", (id, content) => SendFullStatus()); // Dial on string - AppServerController.AddAction(MessagePath + "/dial", - new Action(s => _eisc.SetString(JoinMap.CurrentDialString.JoinNumber, s))); + AddAction("/dial", + (id, content) => + { + var msg = content.ToObject>(); + _eisc.SetString(JoinMap.CurrentDialString.JoinNumber, msg.Value); + }); // Pulse DTMF - AppServerController.AddAction(MessagePath + "/dtmf", new Action(s => + AddAction("/dtmf", (id, content) => { - var join = JoinMap.Joins[s]; + var s = content.ToObject>(); + + var join = JoinMap.Joins[s.Value]; if (join != null) { if (join.JoinNumber > 0) @@ -126,7 +134,7 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle _eisc.PulseBool(join.JoinNumber, 100); } } - })); + }); } /// @@ -134,10 +142,11 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle /// private void SendCallsList() { - PostStatusMessage(new - { - calls = GetCurrentCallList(), - }); + PostStatusMessage(JToken.FromObject(new + { + calls = GetCurrentCallList(), + }) + ); } /// @@ -148,7 +157,7 @@ private List GetCurrentCallList() { return _currentCallItem.Status == eCodecCallStatus.Disconnected ? new List() - : new List {_currentCallItem}; + : new List { _currentCallItem }; } } } \ No newline at end of file diff --git a/3-series/Messengers/SIMPLCameraMessenger.cs b/3-series/Messengers/SIMPLCameraMessenger.cs index 0afb10c..4211146 100644 --- a/3-series/Messengers/SIMPLCameraMessenger.cs +++ b/3-series/Messengers/SIMPLCameraMessenger.cs @@ -1,14 +1,15 @@ -using System; -using System.Collections.Generic; -using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.DeviceSupport; +using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; -using PepperDash.Essentials.Devices.Common.Cameras; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Devices.Common.Cameras; +using System; +using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { -// ReSharper disable once InconsistentNaming + // ReSharper disable once InconsistentNaming public class SIMPLCameraMessenger : MessengerBase { private readonly BasicTriList _eisc; @@ -32,18 +33,16 @@ public SIMPLCameraMessenger(string key, BasicTriList eisc, string messagePath, u #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif { - var asc = appServerController; - - asc.AddAction(MessagePath + "/fullStatus", new Action(SendCameraFullMessageObject)); + AddAction("/fullStatus", (id, content) => SendCameraFullMessageObject()); // Add press and holds using helper action - Action addPhAction = (s, u) => - asc.AddAction(MessagePath + s, new PressAndHoldAction(b => _eisc.SetBool(u, b))); + void addPhAction(string s, uint u) => + AddAction(s, (id, content) => HandleCameraPressAndHold(content, b => _eisc.SetBool(u, b))); addPhAction("/cameraUp", _joinMap.TiltUp.JoinNumber); addPhAction("/cameraDown", _joinMap.TiltDown.JoinNumber); addPhAction("/cameraLeft", _joinMap.PanLeft.JoinNumber); @@ -51,8 +50,8 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle addPhAction("/cameraZoomIn", _joinMap.ZoomIn.JoinNumber); addPhAction("/cameraZoomOut", _joinMap.ZoomOut.JoinNumber); - Action addAction = (s, u) => - asc.AddAction(MessagePath + s, new Action(() => _eisc.PulseBool(u, 100))); + void addAction(string s, uint u) => + AddAction(s, (id, content) => _eisc.PulseBool(u, 100)); addAction("/cameraModeAuto", _joinMap.CameraModeAuto.JoinNumber); addAction("/cameraModeManual", _joinMap.CameraModeManual.JoinNumber); @@ -70,8 +69,23 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle } } + private void HandleCameraPressAndHold(JToken content, Action cameraAction) + { + var state = content.ToObject>(); + + var timerHandler = PressAndHoldHandler.GetPressAndHoldHandler(state.Value); + if (timerHandler == null) + { + return; + } + + timerHandler(state.Value, cameraAction); + + cameraAction(state.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase)); + } + #if SERIES4 - public void CustomUnregsiterWithAppServer(IMobileControl3 appServerController) + public void CustomUnregsiterWithAppServer(IMobileControl appServerController) #else public void CustomUnregsiterWithAppServer(MobileControlSystemController appServerController) #endif @@ -118,12 +132,13 @@ private void SendCameraFullMessageObject() } } - PostStatusMessage(new - { - cameraMode = GetCameraMode(), - hasPresets = _eisc.GetBool(_joinMap.SupportsPresets.JoinNumber), - presets = presetList - }); + PostStatusMessage(JToken.FromObject(new + { + cameraMode = GetCameraMode(), + hasPresets = _eisc.GetBool(_joinMap.SupportsPresets.JoinNumber), + presets = presetList + }) + ); } /// @@ -131,10 +146,10 @@ private void SendCameraFullMessageObject() /// private void PostCameraMode() { - PostStatusMessage(new + PostStatusMessage(JToken.FromObject(new { cameraMode = GetCameraMode() - }); + })); } /// diff --git a/3-series/Messengers/SIMPLDirectRouteMessenger.cs b/3-series/Messengers/SIMPLDirectRouteMessenger.cs index 68584a2..46899cd 100644 --- a/3-series/Messengers/SIMPLDirectRouteMessenger.cs +++ b/3-series/Messengers/SIMPLDirectRouteMessenger.cs @@ -1,13 +1,13 @@ -using System; -using System.Collections.Generic; -using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.DeviceSupport; +using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { - public class SimplDirectRouteMessenger:MessengerBase + public class SimplDirectRouteMessenger : MessengerBase { private readonly BasicTriList _eisc; @@ -27,32 +27,30 @@ public SimplDirectRouteMessenger(string key, BasicTriList eisc, string messagePa #region Overrides of MessengerBase #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 controller) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController controller) #endif { Debug.Console(2, "********** Direct Route Messenger CustomRegisterWithAppServer **********"); - + //Audio source _eisc.SetStringSigAction(JoinMap.SourceForDestinationAudio.JoinNumber, - s => controller.SendMessageObject(new + s => PostStatusMessage(JToken.FromObject(new { - type = MessagePath + "/programAudio/currentSource", - content = new - { - selectedSourceKey = s, - } - })); - - controller.AddAction(MessagePath + "/programAudio/selectSource", - new Action( - s => _eisc.StringInput[JoinMap.SourceForDestinationAudio.JoinNumber].StringValue = s)); + selectedSourceKey = s, + }) + )); + AddAction("/programAudio/selectSource", (id, content) => + { + var msg = content.ToObject>(); + _eisc.StringInput[JoinMap.SourceForDestinationAudio.JoinNumber].StringValue = msg.Value; + }); - controller.AddAction(MessagePath + "/fullStatus", new Action(() => + AddAction("/fullStatus", (id, content) => { foreach (var dest in DestinationList) { @@ -65,45 +63,38 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle UpdateSourceForDestination(source, key); } - controller.SendMessageObject(new + PostStatusMessage(JToken.FromObject(new { - type = MessagePath + "/programAudio/currentSource", - content = new - { - selectedSourceKey = _eisc.StringOutput[JoinMap.SourceForDestinationAudio.JoinNumber].StringValue - } - }); + selectedSourceKey = _eisc.StringOutput[JoinMap.SourceForDestinationAudio.JoinNumber].StringValue + }) + ); - controller.SendMessageObject(new + PostStatusMessage(JToken.FromObject(new { - type = MessagePath + "/advancedSharingMode", - content = new - { - advancedSharingActive = _eisc.BooleanOutput[JoinMap.AdvancedSharingModeFb.JoinNumber].BoolValue - } - }); - })); + advancedSharingActive = _eisc.BooleanOutput[JoinMap.AdvancedSharingModeFb.JoinNumber].BoolValue + }) + ); + }); - controller.AddAction(MessagePath + "/advancedSharingMode",new Action((b) => + AddAction("/advancedSharingMode", (id, content) => { - Debug.Console(1, "Current Sharing Mode: {2}\r\nadvanced sharing mode: {0} join number: {1}", b, + var b = content.ToObject>(); + + Debug.Console(1, "Current Sharing Mode: {2}\r\nadvanced sharing mode: {0} join number: {1}", b.Value, JoinMap.AdvancedSharingModeOn.JoinNumber, _eisc.BooleanOutput[JoinMap.AdvancedSharingModeOn.JoinNumber].BoolValue); - - _eisc.SetBool(JoinMap.AdvancedSharingModeOn.JoinNumber, b); - _eisc.SetBool(JoinMap.AdvancedSharingModeOff.JoinNumber, !b); + + _eisc.SetBool(JoinMap.AdvancedSharingModeOn.JoinNumber, b.Value); + _eisc.SetBool(JoinMap.AdvancedSharingModeOff.JoinNumber, !b.Value); _eisc.PulseBool(JoinMap.AdvancedSharingModeToggle.JoinNumber); - })); + }); _eisc.SetBoolSigAction(JoinMap.AdvancedSharingModeFb.JoinNumber, - (b) => controller.SendMessageObject(new + (b) => PostStatusMessage(JToken.FromObject(new { - type = MessagePath + "/advancedSharingMode", - content = new - { - advancedSharingActive = b - } - })); + advancedSharingActive = b + }) + )); } public void RegisterForDestinationPaths() @@ -117,10 +108,12 @@ public void RegisterForDestinationPaths() _eisc.SetStringSigAction((uint)(JoinMap.SourceForDestinationJoinStart.JoinNumber + dest.Order), s => UpdateSourceForDestination(s, key)); - AppServerController.AddAction(String.Format("{0}/{1}/selectSource", MessagePath, key), - new Action( - s => - _eisc.StringInput[(uint)(JoinMap.SourceForDestinationJoinStart.JoinNumber + dest.Order)].StringValue = s)); + AddAction($"/{key}/selectSource", (id, content) => + { + var s = content.ToObject>(); + + _eisc.StringInput[(uint)(JoinMap.SourceForDestinationJoinStart.JoinNumber + dest.Order)].StringValue = s.Value; + }); } } @@ -128,14 +121,10 @@ public void RegisterForDestinationPaths() private void UpdateSourceForDestination(string sourceKey, string destKey) { - AppServerController.SendMessageObject(new + PostStatusMessage(JToken.FromObject(new { - type = String.Format("{0}/{1}/currentSource", MessagePath, destKey), - content = new - { - selectedSourceKey = sourceKey - } - }); + selectedSourceKey = sourceKey + }), $"{MessagePath}/{destKey}/currentSource"); } } diff --git a/3-series/Messengers/SIMPLRouteMessenger.cs b/3-series/Messengers/SIMPLRouteMessenger.cs index eab8fc2..ccdbb27 100644 --- a/3-series/Messengers/SIMPLRouteMessenger.cs +++ b/3-series/Messengers/SIMPLRouteMessenger.cs @@ -1,5 +1,5 @@ -using System; -using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.DeviceSupport; +using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; @@ -31,21 +31,24 @@ public SIMPLRouteMessenger(string key, BasicTriList eisc, string messagePath, ui } #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif { - appServerController.AddAction(MessagePath + "/fullStatus", - new Action(() => SendRoutingFullMessageObject(_eisc.GetString(_joinStart + StringJoin.CurrentSource)))); + AddAction("/fullStatus", + (id, content) => SendRoutingFullMessageObject(_eisc.GetString(_joinStart + StringJoin.CurrentSource))); - appServerController.AddAction(MessagePath + "/source", - new Action( - c => _eisc.SetString(_joinStart + StringJoin.CurrentSource, c.SourceListItem))); + AddAction("/source", (id, content) => + { + var c = content.ToObject(); + + _eisc.SetString(_joinStart + StringJoin.CurrentSource, c.SourceListItemKey); + }); } #if SERIES4 - public void CustomUnregsiterWithAppServer(IMobileControl3 appServerController) + public void CustomUnregsiterWithAppServer(IMobileControl appServerController) #else public void CustomUnregsiterWithAppServer(MobileControlSystemController appServerController) #endif @@ -64,10 +67,11 @@ private void SendRoutingFullMessageObject(string sourceKey) if (string.IsNullOrEmpty(sourceKey)) sourceKey = "none"; - PostStatusMessage(new - { - selectedSourceKey = sourceKey - }); + PostStatusMessage(JToken.FromObject(new + { + selectedSourceKey = sourceKey + }) + ); } } } \ No newline at end of file diff --git a/3-series/Messengers/SIMPLVtcMessenger.cs b/3-series/Messengers/SIMPLVtcMessenger.cs index 2f5bd99..a421e06 100644 --- a/3-series/Messengers/SIMPLVtcMessenger.cs +++ b/3-series/Messengers/SIMPLVtcMessenger.cs @@ -1,15 +1,16 @@ -using System; -using System.Collections.Generic; -using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.DeviceSupport; +using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; -using PepperDash.Essentials.Devices.Common.Codec; -using PepperDash.Essentials.Devices.Common.Cameras; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Devices.Common.Cameras; +using PepperDash.Essentials.Devices.Common.Codec; +using System; +using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { -// ReSharper disable once InconsistentNaming + // ReSharper disable once InconsistentNaming public class SIMPLVtcMessenger : MessengerBase { private readonly BasicTriList _eisc; @@ -35,7 +36,7 @@ public SIMPLVtcMessenger(string key, BasicTriList eisc, string messagePath) JoinMap = new SIMPLVtcJoinMap(1001); - _currentCallItem = new CodecActiveCallItem {Type = eCodecCallType.Video, Id = "-video-"}; + _currentCallItem = new CodecActiveCallItem { Type = eCodecCallType.Video, Id = "-video-" }; } /// @@ -43,15 +44,14 @@ public SIMPLVtcMessenger(string key, BasicTriList eisc, string messagePath) /// /// #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif - { - var asc = appServerController; + { _eisc.SetStringSigAction(JoinMap.HookState.JoinNumber, s => { - _currentCallItem.Status = (eCodecCallStatus) Enum.Parse(typeof (eCodecCallStatus), s, true); + _currentCallItem.Status = (eCodecCallStatus)Enum.Parse(typeof(eCodecCallStatus), s, true); PostFullStatus(); // SendCallsList(); }); @@ -69,7 +69,7 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle _eisc.SetStringSigAction(JoinMap.CallDirection.JoinNumber, s => { - _currentCallItem.Direction = (eCodecCallDirection) Enum.Parse(typeof (eCodecCallDirection), s, true); + _currentCallItem.Direction = (eCodecCallDirection)Enum.Parse(typeof(eCodecCallDirection), s, true); PostCallsList(); }); @@ -95,13 +95,13 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle PostCallsList(); }); - _eisc.SetStringSigAction(JoinMap.IncomingCallName.JoinNumber, s => + _eisc.SetStringSigAction(JoinMap.IncomingCallName.JoinNumber, s => { - if(_incomingCallItem != null) + if (_incomingCallItem != null) { _incomingCallItem.Name = s; PostCallsList(); - } + } }); _eisc.SetStringSigAction(JoinMap.IncomingCallNumber.JoinNumber, s => @@ -113,14 +113,14 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle } }); - _eisc.SetBoolSigAction(JoinMap.CameraSupportsAutoMode.JoinNumber, b => PostStatusMessage(new + _eisc.SetBoolSigAction(JoinMap.CameraSupportsAutoMode.JoinNumber, b => PostStatusMessage(JToken.FromObject(new { cameraSupportsAutoMode = b - })); - _eisc.SetBoolSigAction(JoinMap.CameraSupportsOffMode.JoinNumber, b => PostStatusMessage(new + }))); + _eisc.SetBoolSigAction(JoinMap.CameraSupportsOffMode.JoinNumber, b => PostStatusMessage(JToken.FromObject(new { cameraSupportsOffMode = b - })); + }))); // Directory insanity _eisc.SetUShortSigAction(JoinMap.DirectoryRowCount.JoinNumber, u => @@ -136,42 +136,42 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle _previousDirectoryLength = u; }); - _eisc.SetStringSigAction(JoinMap.DirectoryEntrySelectedName.JoinNumber, s => PostStatusMessage(new + _eisc.SetStringSigAction(JoinMap.DirectoryEntrySelectedName.JoinNumber, s => PostStatusMessage(JToken.FromObject(new { directoryContactSelected = new { name = _eisc.GetString(JoinMap.DirectoryEntrySelectedName.JoinNumber), } - })); + }))); - _eisc.SetStringSigAction(JoinMap.DirectoryEntrySelectedNumber.JoinNumber, s => PostStatusMessage(new + _eisc.SetStringSigAction(JoinMap.DirectoryEntrySelectedNumber.JoinNumber, s => PostStatusMessage(JToken.FromObject(new { directoryContactSelected = new { number = _eisc.GetString(JoinMap.DirectoryEntrySelectedNumber.JoinNumber), } - })); + }))); - _eisc.SetStringSigAction(JoinMap.DirectorySelectedFolderName.JoinNumber, s => PostStatusMessage(new + _eisc.SetStringSigAction(JoinMap.DirectorySelectedFolderName.JoinNumber, s => PostStatusMessage(JToken.FromObject(new { directorySelectedFolderName = _eisc.GetString(JoinMap.DirectorySelectedFolderName.JoinNumber) - })); + }))); _eisc.SetSigTrueAction(JoinMap.CameraModeAuto.JoinNumber, PostCameraMode); _eisc.SetSigTrueAction(JoinMap.CameraModeManual.JoinNumber, PostCameraMode); _eisc.SetSigTrueAction(JoinMap.CameraModeOff.JoinNumber, PostCameraMode); - _eisc.SetBoolSigAction(JoinMap.CameraSelfView.JoinNumber, b => PostStatusMessage(new + _eisc.SetBoolSigAction(JoinMap.CameraSelfView.JoinNumber, b => PostStatusMessage(JToken.FromObject(new { cameraSelfView = b - })); + }))); _eisc.SetUShortSigAction(JoinMap.CameraNumberSelect.JoinNumber, u => PostSelectedCamera()); // Add press and holds using helper action - Action addPhAction = (s, u) => - AppServerController.AddAction(MessagePath + s, new PressAndHoldAction(b => _eisc.SetBool(u, b))); + void addPhAction(string s, uint u) => + AddAction(s, (id, content) => HandleCameraPressAndHold(content, b => _eisc.SetBool(u, b))); addPhAction("/cameraUp", JoinMap.CameraTiltUp.JoinNumber); addPhAction("/cameraDown", JoinMap.CameraTiltDown.JoinNumber); addPhAction("/cameraLeft", JoinMap.CameraPanLeft.JoinNumber); @@ -180,8 +180,8 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle addPhAction("/cameraZoomOut", JoinMap.CameraZoomOut.JoinNumber); // Add straight pulse calls using helper action - Action addAction = (s, u) => - AppServerController.AddAction(MessagePath + s, new Action(() => _eisc.PulseBool(u, 100))); + void addAction(string s, uint u) => + AddAction(s, (id, content) => _eisc.PulseBool(u, 100)); addAction("/endCallById", JoinMap.EndCall.JoinNumber); addAction("/endAllCalls", JoinMap.EndCall.JoinNumber); addAction("/acceptById", JoinMap.IncomingAnswer.JoinNumber); @@ -203,7 +203,11 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle addAction("/cameraSelfView", JoinMap.CameraSelfView.JoinNumber); addAction("/cameraLayout", JoinMap.CameraLayout.JoinNumber); - asc.AddAction("/cameraSelect", new Action(SelectCamera)); + AddAction("/cameraSelect", (id, content) => + { + var s = content.ToObject>(); + SelectCamera(s.Value); + }); // camera presets for (uint i = 0; i < 6; i++) @@ -211,16 +215,21 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle addAction("/cameraPreset" + (i + 1), JoinMap.CameraPresetStart.JoinNumber + i); } - asc.AddAction(MessagePath + "/isReady", new Action(PostIsReady)); + AddAction("/isReady", (id, content) => PostIsReady()); // Get status - asc.AddAction(MessagePath + "/fullStatus", new Action(PostFullStatus)); + AddAction("/fullStatus", (id, content) => PostFullStatus()); // Dial on string - asc.AddAction(MessagePath + "/dial", new Action(s => - _eisc.SetString(JoinMap.CurrentDialString.JoinNumber, s))); + AddAction("/dial", (id, content) => + { + var s = content.ToObject>(); + + _eisc.SetString(JoinMap.CurrentDialString.JoinNumber, s.Value); + }); // Pulse DTMF - AppServerController.AddAction(MessagePath + "/dtmf", new Action(s => + AddAction("/dtmf", (id, content) => { - var join = JoinMap.Joins[s]; + var s = content.ToObject>(); + var join = JoinMap.Joins[s.Value]; if (join != null) { if (join.JoinNumber > 0) @@ -228,19 +237,20 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle _eisc.PulseBool(join.JoinNumber, 100); } } - })); + }); // Directory madness - asc.AddAction(MessagePath + "/directoryRoot", - new Action(() => _eisc.PulseBool(JoinMap.DirectoryRoot.JoinNumber))); - asc.AddAction(MessagePath + "/directoryBack", - new Action(() => _eisc.PulseBool(JoinMap.DirectoryFolderBack.JoinNumber))); - asc.AddAction(MessagePath + "/directoryById", new Action(s => + AddAction("/directoryRoot", + (id, content) => _eisc.PulseBool(JoinMap.DirectoryRoot.JoinNumber)); + AddAction("/directoryBack", + (id, content) => _eisc.PulseBool(JoinMap.DirectoryFolderBack.JoinNumber)); + AddAction("/directoryById", (id, content) => { + var s = content.ToObject>(); // the id should contain the line number to forward to simpl try { - var u = ushort.Parse(s); + var u = ushort.Parse(s.Value); _eisc.SetUshort(JoinMap.DirectorySelectRow.JoinNumber, u); _eisc.PulseBool(JoinMap.DirectoryLineSelected.JoinNumber); } @@ -249,12 +259,13 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "/directoryById request contains non-numeric ID incompatible with SIMPL bridge"); } - })); - asc.AddAction(MessagePath + "/directorySelectContact", new Action(s => + }); + AddAction("/directorySelectContact", (id, content) => { + var s = content.ToObject>(); try { - var u = ushort.Parse(s); + var u = ushort.Parse(s.Value); _eisc.SetUshort(JoinMap.DirectorySelectRow.JoinNumber, u); _eisc.PulseBool(JoinMap.DirectoryLineSelected.JoinNumber); } @@ -262,10 +273,10 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle { Debug.Console(2, this, "Error parsing contact from {0} for path /directorySelectContact", s); } - })); - asc.AddAction(MessagePath + "/directoryDialContact", - new Action(() => _eisc.PulseBool(JoinMap.DirectoryDialSelectedLine.JoinNumber))); - asc.AddAction(MessagePath + "/getDirectory", new Action(() => + }); + AddAction("/directoryDialContact", + (id, content) => _eisc.PulseBool(JoinMap.DirectoryDialSelectedLine.JoinNumber)); + AddAction("/getDirectory", (id, content) => { if (_eisc.GetUshort(JoinMap.DirectoryRowCount.JoinNumber) > 0) { @@ -275,15 +286,31 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle { _eisc.PulseBool(JoinMap.DirectoryRoot.JoinNumber); } - })); + }); + } + + private void HandleCameraPressAndHold(JToken content, Action cameraAction) + { + var state = content.ToObject>(); + + var timerHandler = PressAndHoldHandler.GetPressAndHoldHandler(state.Value); + if (timerHandler == null) + { + return; + } + + timerHandler(state.Value, cameraAction); + + cameraAction(state.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase)); } /// /// /// + /// private void PostFullStatus() { - PostStatusMessage(new + PostStatusMessage(JToken.FromObject(new { calls = GetCurrentCallList(), cameraMode = GetCameraMode(), @@ -305,7 +332,7 @@ private void PostFullStatus() hasCameras = true, showCamerasWhenNotInCall = _eisc.BooleanOutput[503].BoolValue, selectedCamera = GetSelectedCamera(), - }); + })); } /// @@ -346,7 +373,7 @@ private void PostDirectory() directoryResults = items } }; - PostStatusMessage(directoryMessage); + PostStatusMessage(JToken.FromObject(directoryMessage)); } /// @@ -354,10 +381,10 @@ private void PostDirectory() /// private void PostCameraMode() { - PostStatusMessage(new + PostStatusMessage(JToken.FromObject(new { cameraMode = GetCameraMode() - }); + })); } /// @@ -375,10 +402,10 @@ private string GetCameraMode() private void PostSelectedCamera() { - PostStatusMessage(new + PostStatusMessage(JToken.FromObject(new { selectedCamera = GetSelectedCamera() - }); + })); } /// @@ -404,10 +431,10 @@ private string GetSelectedCamera() /// private void PostIsReady() { - PostStatusMessage(new + PostStatusMessage(JToken.FromObject(new { isReady = true - }); + })); } /// @@ -415,10 +442,10 @@ private void PostIsReady() /// private void PostCallsList() { - PostStatusMessage(new + PostStatusMessage(JToken.FromObject(new { calls = GetCurrentCallList(), - }); + })); } /// @@ -429,7 +456,7 @@ private void SelectCamera(string s) { var cam = s.Substring(6); _eisc.SetUshort(JoinMap.CameraNumberSelect.JoinNumber, - (ushort) (cam.ToLower() == "far" ? 100 : UInt16.Parse(cam))); + (ushort)(cam.ToLower() == "far" ? 100 : ushort.Parse(cam))); } /// diff --git a/3-series/Messengers/ShadeBaseMessenger.cs b/3-series/Messengers/ShadeBaseMessenger.cs index fb4ecc7..e004153 100644 --- a/3-series/Messengers/ShadeBaseMessenger.cs +++ b/3-series/Messengers/ShadeBaseMessenger.cs @@ -1,87 +1,77 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - +using Newtonsoft.Json; using PepperDash.Core; -using PepperDash.Essentials.Core.Shades; - -using Newtonsoft.Json; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Core.Shades; +using System; namespace PepperDash.Essentials.AppServer.Messengers { - public class ShadeBaseMessenger : MessengerBase + public class IShadesOpenCloseStopMessenger : MessengerBase { - protected ShadeBase Device { get; private set; } + private readonly IShadesOpenCloseStop device; - public ShadeBaseMessenger(string key, ShadeBase device, string messagePath) - : base(key, messagePath, device) + public IShadesOpenCloseStopMessenger(string key, IShadesOpenCloseStop shades, string messagePath) + : base(key, messagePath, shades as Device) { - if (device == null) - { - throw new ArgumentNullException("device"); - } - - Device = device; + device = shades; } #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif { - base.CustomRegisterWithAppServer(appServerController); + base.RegisterActions(); - appServerController.AddAction(string.Format("{0}/fullStatus", MessagePath), new Action(SendFullStatus)); + AddAction("/fullStatus", (id, content) => SendFullStatus()); - appServerController.AddAction(string.Format("{0}/shadeUp", MessagePath), new Action( () => + AddAction("/shadeUp", (id, content) => { - Device.Open(); + device.Open(); - })); + }); - appServerController.AddAction(string.Format("{0}/shadeDown", MessagePath), new Action(() => + AddAction("/shadeDown", (id, content) => { - Device.Close(); + device.Close(); - })); + }); - var stopDevice = Device as IShadesOpenCloseStop; + var stopDevice = device; if (stopDevice != null) { - appServerController.AddAction(string.Format("{0}/stopOrPreset", MessagePath), new Action(() => + AddAction("/stopOrPreset", (id, content) => { stopDevice.Stop(); - })); + }); } - var feedbackDevice = Device as IShadesOpenClosedFeedback; - if (feedbackDevice != null) + if (device is IShadesOpenClosedFeedback feedbackDevice) { - feedbackDevice.ShadeIsOpenFeedback.OutputChange += new EventHandler(ShadeIsOpenFeedback_OutputChange); - feedbackDevice.ShadeIsClosedFeedback.OutputChange += new EventHandler(ShadeIsClosedFeedback_OutputChange); + feedbackDevice.ShadeIsOpenFeedback.OutputChange += new EventHandler(ShadeIsOpenFeedback_OutputChange); + feedbackDevice.ShadeIsClosedFeedback.OutputChange += new EventHandler(ShadeIsClosedFeedback_OutputChange); } } - void ShadeIsOpenFeedback_OutputChange(object sender, PepperDash.Essentials.Core.FeedbackEventArgs e) + private void ShadeIsOpenFeedback_OutputChange(object sender, Core.FeedbackEventArgs e) { - var state = new ShadeBaseStateMessage(); - - state.IsOpen = e.BoolValue; + var state = new ShadeBaseStateMessage + { + IsOpen = e.BoolValue + }; PostStatusMessage(state); } - void ShadeIsClosedFeedback_OutputChange(object sender, PepperDash.Essentials.Core.FeedbackEventArgs e) + private void ShadeIsClosedFeedback_OutputChange(object sender, Core.FeedbackEventArgs e) { - var state = new ShadeBaseStateMessage(); - - state.IsClosed = e.BoolValue; + var state = new ShadeBaseStateMessage + { + IsClosed = e.BoolValue + }; PostStatusMessage(state); } @@ -91,8 +81,7 @@ private void SendFullStatus() { var state = new ShadeBaseStateMessage(); - var feedbackDevice = Device as IShadesOpenClosedFeedback; - if (feedbackDevice != null) + if (device is IShadesOpenClosedFeedback feedbackDevice) { state.IsOpen = feedbackDevice.ShadeIsOpenFeedback.BoolValue; state.IsClosed = feedbackDevice.ShadeIsClosedFeedback.BoolValue; diff --git a/3-series/Messengers/SystemMonitorMessenger.cs b/3-series/Messengers/SystemMonitorMessenger.cs index 05ced47..92ffd63 100644 --- a/3-series/Messengers/SystemMonitorMessenger.cs +++ b/3-series/Messengers/SystemMonitorMessenger.cs @@ -1,26 +1,26 @@ -using System; -using Crestron.SimplSharp; +using Crestron.SimplSharp; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using PepperDash.Core; -using PepperDash.Essentials.Core.Monitoring; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Core.Monitoring; +using System; +using System.Threading.Tasks; namespace PepperDash.Essentials.AppServer.Messengers { public class SystemMonitorMessenger : MessengerBase { - public SystemMonitorController SysMon { get; private set; } + private readonly SystemMonitorController systemMonitor; public SystemMonitorMessenger(string key, SystemMonitorController sysMon, string messagePath) - : base(key, messagePath) + : base(key, messagePath, sysMon) { - if (sysMon == null) - throw new ArgumentNullException("sysMon"); + systemMonitor = sysMon ?? throw new ArgumentNullException("sysMon"); - SysMon = sysMon; + systemMonitor.SystemMonitorPropertiesChanged += SysMon_SystemMonitorPropertiesChanged; - SysMon.SystemMonitorPropertiesChanged += SysMon_SystemMonitorPropertiesChanged; - - foreach (var p in SysMon.ProgramStatusFeedbackCollection) + foreach (var p in systemMonitor.ProgramStatusFeedbackCollection) { p.Value.ProgramInfoChanged += ProgramInfoChanged; } @@ -39,7 +39,8 @@ private void ProgramInfoChanged(object sender, ProgramInfoEventArgs e) if (e.ProgramInfo != null) { //Debug.Console(1, "Posting Status Message: {0}", e.ProgramInfo.ToString()); - PostStatusMessage(e.ProgramInfo); + PostStatusMessage(JToken.FromObject(e.ProgramInfo) + ); } } @@ -57,9 +58,10 @@ private void SendFullStatusMessage() { SendSystemMonitorStatusMessage(); - foreach (var p in SysMon.ProgramStatusFeedbackCollection) + foreach (var p in systemMonitor.ProgramStatusFeedbackCollection) { - PostStatusMessage(p.Value.ProgramInfo); + PostStatusMessage(JToken.FromObject(p.Value.ProgramInfo) + ); } } @@ -68,24 +70,47 @@ private void SendSystemMonitorStatusMessage() Debug.Console(1, "Posting System Monitor Status Message."); // This takes a while, launch a new thread - CrestronInvoke.BeginInvoke(o => PostStatusMessage(new - { - timeZone = SysMon.TimeZoneFeedback.IntValue, - timeZoneName = SysMon.TimeZoneTextFeedback.StringValue, - ioControllerVersion = SysMon.IoControllerVersionFeedback.StringValue, - snmpVersion = SysMon.SnmpVersionFeedback.StringValue, - bacnetVersion = SysMon.BaCnetAppVersionFeedback.StringValue, - controllerVersion = SysMon.ControllerVersionFeedback.StringValue - })); + Task.Run(() => PostStatusMessage(JToken.FromObject(new SystemMonitorStateMessage + { + + TimeZone = systemMonitor.TimeZoneFeedback.IntValue, + TimeZoneName = systemMonitor.TimeZoneTextFeedback.StringValue, + IoControllerVersion = systemMonitor.IoControllerVersionFeedback.StringValue, + SnmpVersion = systemMonitor.SnmpVersionFeedback.StringValue, + BacnetVersion = systemMonitor.BaCnetAppVersionFeedback.StringValue, + ControllerVersion = systemMonitor.ControllerVersionFeedback.StringValue + }) + )); } #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif { - AppServerController.AddAction(MessagePath + "/fullStatus", new Action(SendFullStatusMessage)); + AddAction("/fullStatus", (id, content) => SendFullStatusMessage()); } } + + public class SystemMonitorStateMessage + { + [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] + public int TimeZone { get; set; } + + [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] + public string TimeZoneName { get; set; } + + [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] + public string IoControllerVersion { get; set; } + + [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] + public string SnmpVersion { get; set; } + + [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] + public string BacnetVersion { get; set; } + + [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] + public string ControllerVersion { get; set; } + } } \ No newline at end of file diff --git a/3-series/Messengers/TwoWayDisplayBaseMessenger.cs b/3-series/Messengers/TwoWayDisplayBaseMessenger.cs index cc95fc7..baf970d 100644 --- a/3-series/Messengers/TwoWayDisplayBaseMessenger.cs +++ b/3-series/Messengers/TwoWayDisplayBaseMessenger.cs @@ -1,14 +1,13 @@ -using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using TwoWayDisplayBase = PepperDash.Essentials.Devices.Common.Displays.TwoWayDisplayBase; namespace PepperDash.Essentials.AppServer.Messengers { - public class TwoWayDisplayBaseMessenger:MessengerBase + public class TwoWayDisplayBaseMessenger : MessengerBase { - private const string PowerStatusPath = "/powerStatus"; - private const string InputStatusPath = "/inputStatus"; - private readonly TwoWayDisplayBase _display; public TwoWayDisplayBaseMessenger(string key, string messagePath) : base(key, messagePath) @@ -25,26 +24,26 @@ public TwoWayDisplayBaseMessenger(string key, string messagePath, TwoWayDisplayB public void SendFullStatus() { - var messageObj = new + var messageObj = new TwoWayDisplayBaseStateMessage { - powerState = _display.PowerIsOnFeedback.BoolValue, - currentInput = _display.CurrentInputFeedback.StringValue + //PowerState = _display.PowerIsOnFeedback.BoolValue, + CurrentInput = _display.CurrentInputFeedback.StringValue }; PostStatusMessage(messageObj); } #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif { - base.CustomRegisterWithAppServer(appServerController); + base.RegisterActions(); - appServerController.AddAction(MessagePath + "/fullStatus", new Action(SendFullStatus)); + AddAction("/fullStatus", (id, content) => SendFullStatus()); - _display.PowerIsOnFeedback.OutputChange += PowerIsOnFeedbackOnOutputChange; + //_display.PowerIsOnFeedback.OutputChange += PowerIsOnFeedbackOnOutputChange; _display.CurrentInputFeedback.OutputChange += CurrentInputFeedbackOnOutputChange; _display.IsCoolingDownFeedback.OutputChange += IsCoolingFeedbackOnOutputChange; _display.IsWarmingUpFeedback.OutputChange += IsWarmingFeedbackOnOutputChange; @@ -52,61 +51,52 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle private void CurrentInputFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) { - var messageObj = new - { - type = MessagePath, - content = new + PostStatusMessage(JToken.FromObject(new { currentInput = feedbackEventArgs.StringValue - } - }; - - AppServerController.SendMessageObject(messageObj); + }) + ); } - private void PowerIsOnFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) - { - var messageObj = new - { - type = MessagePath, - content = new - { - powerState = feedbackEventArgs.BoolValue - } - }; - - AppServerController.SendMessageObject(messageObj); - } + //private void PowerIsOnFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) + //{ + // PostStatusMessage(JToken.FromObject(new + // { + // powerState = feedbackEventArgs.BoolValue + // }) + // ); + //} private void IsWarmingFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) { - var messageObj = new - { - type = MessagePath, - content = new + PostStatusMessage(JToken.FromObject(new { isWarming = feedbackEventArgs.BoolValue - } - }; - - AppServerController.SendMessageObject(messageObj); + }) + ); } private void IsCoolingFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) { - var messageObj = new - { - type = MessagePath, - content = new + PostStatusMessage(JToken.FromObject(new { isCooling = feedbackEventArgs.BoolValue - } - }; + }) + ); - AppServerController.SendMessageObject(messageObj); + } #endregion } + + public class TwoWayDisplayBaseStateMessage : DeviceStateMessageBase + { + //[JsonProperty("powerState", NullValueHandling = NullValueHandling.Ignore)] + //public bool? PowerState { get; set; } + + [JsonProperty("currentInput", NullValueHandling = NullValueHandling.Ignore)] + public string CurrentInput { get; set; } + } } \ No newline at end of file diff --git a/3-series/Messengers/VideoCodecBaseMessenger.cs b/3-series/Messengers/VideoCodecBaseMessenger.cs index 2bc8aa7..fecbc68 100644 --- a/3-series/Messengers/VideoCodecBaseMessenger.cs +++ b/3-series/Messengers/VideoCodecBaseMessenger.cs @@ -1,16 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using Crestron.SimplSharp; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; -using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.Cameras; +using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; -using Crestron.SimplSharp; -using PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom; -using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using static PepperDash.Essentials.AppServer.Messengers.VideoCodecBaseStateMessage.CameraStatus; namespace PepperDash.Essentials.AppServer.Messengers { @@ -35,27 +36,21 @@ public class VideoCodecBaseMessenger : MessengerBase public VideoCodecBaseMessenger(string key, VideoCodecBase codec, string messagePath) : base(key, messagePath, codec) { - if (codec == null) - throw new ArgumentNullException("codec"); + Codec = codec ?? throw new ArgumentNullException("codec"); + codec.CallStatusChange += Codec_CallStatusChange; + codec.IsReadyChange += Codec_IsReadyChange; - Codec = codec; - codec.CallStatusChange += codec_CallStatusChange; - codec.IsReadyChange += codec_IsReadyChange; - - var dirCodec = codec as IHasDirectory; - if (dirCodec != null) + if (codec is IHasDirectory dirCodec) { - dirCodec.DirectoryResultReturned += dirCodec_DirectoryResultReturned; + dirCodec.DirectoryResultReturned += DirCodec_DirectoryResultReturned; } - var recCodec = codec as IHasCallHistory; - if (recCodec != null) + if (codec is IHasCallHistory recCodec) { recCodec.CallHistory.RecentCallsListHasChanged += CallHistory_RecentCallsListHasChanged; } - var pwPromptCodec = codec as IPasswordPrompt; - if (pwPromptCodec != null) + if (codec is IPasswordPrompt pwPromptCodec) { pwPromptCodec.PasswordRequired += OnPasswordRequired; } @@ -63,16 +58,15 @@ public VideoCodecBaseMessenger(string key, VideoCodecBase codec, string messageP private void OnPasswordRequired(object sender, PasswordPromptEventArgs args) { - var eventMsg = new PasswordPromptEventMessage() + var eventMsg = new PasswordPromptEventMessage { Message = args.Message, LastAttemptWasIncorrect = args.LastAttemptWasIncorrect, LoginAttemptFailed = args.LoginAttemptFailed, LoginAttemptCancelled = args.LoginAttemptCancelled, + EventType = "passwordPrompt" }; - eventMsg.EventType = "passwordPrompt"; - PostEventMessage(eventMsg); } @@ -85,8 +79,7 @@ private void CallHistory_RecentCallsListHasChanged(object sender, EventArgs e) { var state = new VideoCodecBaseStateMessage(); - var codecCallHistory = sender as CodecCallHistory; - if (codecCallHistory == null) return; + if (!(sender is CodecCallHistory codecCallHistory)) return; var recents = codecCallHistory.RecentCalls; if (recents != null) @@ -102,10 +95,9 @@ private void CallHistory_RecentCallsListHasChanged(object sender, EventArgs e) /// /// /// - protected virtual void dirCodec_DirectoryResultReturned(object sender, DirectoryEventArgs e) + protected virtual void DirCodec_DirectoryResultReturned(object sender, DirectoryEventArgs e) { - var hasDirectory = Codec as IHasDirectory; - if (hasDirectory != null) + if (Codec is IHasDirectory) SendDirectory(e.Directory); } @@ -116,9 +108,8 @@ protected void SendDirectory(CodecDirectory directory) { var state = new VideoCodecBaseStateMessage(); - var dirCodec = Codec as IHasDirectory; - if (dirCodec != null) + if (Codec is IHasDirectory dirCodec) { Debug.Console(2, this, "Sending Directory. Directory Item Count: {0}", directory.CurrentDirectoryResults.Count); @@ -126,62 +117,18 @@ protected void SendDirectory(CodecDirectory directory) state.CurrentDirectory = directory; CrestronInvoke.BeginInvoke((o) => PostStatusMessage(state)); -/* var directoryMessage = new - { - currentDirectory = new - { - directoryResults = prefixedDirectoryResults, - isRootDirectory = isRoot - } - }; - - //Spool up a thread in case this is a large quantity of data - CrestronInvoke.BeginInvoke((o) => PostStatusMessage(directoryMessage)); */ - } - } - - /// - /// Iterates a directory object and prefixes any folder items with "[+] " - /// - /// - /// - [Obsolete("Deprected in favour of processing in the Angular App")] - private CodecDirectory PrefixDirectoryFolderItems(CodecDirectory directory) - { - var tempCodecDirectory = new CodecDirectory(); - var tempDirectoryList = new List(); - - if (directory.CurrentDirectoryResults.Count > 0) - { - foreach (var item in directory.CurrentDirectoryResults) - { - if (item is DirectoryFolder) - { - var newFolder = (DirectoryFolder) item.Clone(); - - var prefixName = "[+] " + newFolder.Name; - - newFolder.Name = prefixName; - - tempDirectoryList.Add(newFolder); - } - else - { - tempDirectoryList.Add(item); - } - } + /* var directoryMessage = new + { + currentDirectory = new + { + directoryResults = prefixedDirectoryResults, + isRootDirectory = isRoot + } + }; + + //Spool up a thread in case this is a large quantity of data + CrestronInvoke.BeginInvoke((o) => PostStatusMessage(directoryMessage)); */ } - //else - //{ - // DirectoryItem noResults = new DirectoryItem() { Name = "No Results Found" }; - - // tempDirectoryList.Add(noResults); - //} - - tempCodecDirectory.AddContactsToDirectory(tempDirectoryList.OfType().Cast().ToList()); - tempCodecDirectory.AddFoldersToDirectory(tempDirectoryList.OfType().Cast().ToList()); - - return tempCodecDirectory; } /// @@ -189,11 +136,12 @@ private CodecDirectory PrefixDirectoryFolderItems(CodecDirectory directory) /// /// /// - private void codec_IsReadyChange(object sender, EventArgs e) + private void Codec_IsReadyChange(object sender, EventArgs e) { - var state = new VideoCodecBaseStateMessage(); - - state.IsReady = true; + var state = new VideoCodecBaseStateMessage + { + IsReady = true + }; PostStatusMessage(state); @@ -205,149 +153,186 @@ private void codec_IsReadyChange(object sender, EventArgs e) /// /// #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif { try { - base.CustomRegisterWithAppServer(appServerController); + base.RegisterActions(); + + AddAction("/isReady", (id, content) => SendIsReady()); + + AddAction("/fullStatus", (id, content) => SendFullStatus()); + + AddAction("/dial", (id, content) => + { + var value = content.ToObject>(); + + Codec.Dial(value.Value); + }); + + AddAction("/dialMeeting", (id, content) => Codec.Dial(content.ToObject())); - appServerController.AddAction(String.Format("{0}/isReady", MessagePath), new Action(SendIsReady)); - appServerController.AddAction(String.Format("{0}/fullStatus", MessagePath), new Action(SendFullStatus)); - appServerController.AddAction(String.Format("{0}/dial", MessagePath), new Action(s => Codec.Dial(s))); - appServerController.AddAction(String.Format("{0}/dialMeeting", MessagePath), new Action(m => Codec.Dial(m))); - appServerController.AddAction(String.Format("{0}/endCallById", MessagePath), new Action(s => + AddAction("/endCallById", (id, content) => { - var call = GetCallWithId(s); + var s = content.ToObject>(); + var call = GetCallWithId(s.Value); if (call != null) Codec.EndCall(call); - })); - appServerController.AddAction(MessagePath + "/endAllCalls", new Action(Codec.EndAllCalls)); - appServerController.AddAction(MessagePath + "/dtmf", new Action(s => Codec.SendDtmf(s))); - appServerController.AddAction(MessagePath + "/rejectById", new Action(s => + }); + + AddAction("/endAllCalls", (id, content) => Codec.EndAllCalls()); + + AddAction("/dtmf", (id, content) => { - var call = GetCallWithId(s); + var s = content.ToObject>(); + Codec.SendDtmf(s.Value); + }); + + AddAction("/rejectById", (id, content) => + { + var s = content.ToObject>(); + + var call = GetCallWithId(s.Value); if (call != null) Codec.RejectCall(call); - })); - appServerController.AddAction(MessagePath + "/acceptById", new Action(s => + }); + + AddAction("/acceptById", (id, content) => { - var call = GetCallWithId(s); + var s = content.ToObject>(); + + var call = GetCallWithId(s.Value); if (call != null) Codec.AcceptCall(call); - })); + }); Codec.SharingContentIsOnFeedback.OutputChange += SharingContentIsOnFeedback_OutputChange; Codec.SharingSourceFeedback.OutputChange += SharingSourceFeedback_OutputChange; // Directory actions - var dirCodec = Codec as IHasDirectory; - if (dirCodec != null) + if (Codec is IHasDirectory dirCodec) { - appServerController.AddAction(MessagePath + "/getDirectory", new Action(GetDirectoryRoot)); - appServerController.AddAction(MessagePath + "/directoryById", new Action(GetDirectory)); - appServerController.AddAction(MessagePath + "/directorySearch", new Action(DirectorySearch)); - appServerController.AddAction(MessagePath + "/directoryBack", new Action(GetPreviousDirectory)); + AddAction("/getDirectory", (id, content) => GetDirectoryRoot()); + + AddAction("/directoryById", (id, content) => + { + var msg = content.ToObject>(); + GetDirectory(msg.Value); + }); + + AddAction("/directorySearch", (id, content) => + { + var msg = content.ToObject>(); + + GetDirectory(msg.Value); + }); + + AddAction("/directoryBack", (id, content) => GetPreviousDirectory()); dirCodec.PhonebookSyncState.InitialSyncCompleted += PhonebookSyncState_InitialSyncCompleted; } // History actions - var recCodec = Codec as IHasCallHistory; - if (recCodec != null) + if (Codec is IHasCallHistory recCodec) { - appServerController.AddAction(MessagePath + "/getCallHistory", new Action(PostCallHistory)); + AddAction("/getCallHistory", (id, content) => PostCallHistory()); } - var cameraCodec = Codec as IHasCodecCameras; - if (cameraCodec != null) + if (Codec is IHasCodecCameras cameraCodec) { Debug.Console(2, this, "Adding IHasCodecCameras Actions"); - cameraCodec.CameraSelected += cameraCodec_CameraSelected; + cameraCodec.CameraSelected += CameraCodec_CameraSelected; + + AddAction("/cameraSelect", (id, content) => + { + var msg = content.ToObject>(); + + cameraCodec.SelectCamera(msg.Value); + }); - appServerController.AddAction(MessagePath + "/cameraSelect", - new Action(cameraCodec.SelectCamera)); MapCameraActions(); - var presetsCodec = Codec as IHasCodecRoomPresets; - if (presetsCodec != null) + if (Codec is IHasCodecRoomPresets presetsCodec) { Debug.Console(2, this, "Adding IHasCodecRoomPresets Actions"); - presetsCodec.CodecRoomPresetsListHasChanged += presetsCodec_CameraPresetsListHasChanged; + presetsCodec.CodecRoomPresetsListHasChanged += PresetsCodec_CameraPresetsListHasChanged; + + AddAction("/cameraPreset", (id, content) => + { + var msg = content.ToObject>(); + + presetsCodec.CodecRoomPresetSelect(msg.Value); + }); + + AddAction("/cameraPresetStore", (id, content) => + { + var msg = content.ToObject(); - appServerController.AddAction(MessagePath + "/cameraPreset", - new Action(presetsCodec.CodecRoomPresetSelect)); - appServerController.AddAction(MessagePath + "/cameraPresetStore", - new Action(p => presetsCodec.CodecRoomPresetStore(p.ID, p.Description))); + presetsCodec.CodecRoomPresetStore(msg.ID, msg.Description); + }); } - var speakerTrackCodec = Codec as IHasCameraAutoMode; - if (speakerTrackCodec != null) + if (Codec is IHasCameraAutoMode speakerTrackCodec) { Debug.Console(2, this, "Adding IHasCameraAutoMode Actions"); speakerTrackCodec.CameraAutoModeIsOnFeedback.OutputChange += CameraAutoModeIsOnFeedback_OutputChange; - appServerController.AddAction(MessagePath + "/cameraModeAuto", - new Action(speakerTrackCodec.CameraAutoModeOn)); - appServerController.AddAction(MessagePath + "/cameraModeManual", - new Action(speakerTrackCodec.CameraAutoModeOff)); + AddAction("/cameraModeAuto", (id, content) => speakerTrackCodec.CameraAutoModeOn()); + + AddAction("/cameraModeManual", (id, content) => speakerTrackCodec.CameraAutoModeOff()); } - var cameraOffCodec = Codec as IHasCameraOff; - if (cameraOffCodec != null) + if (Codec is IHasCameraOff cameraOffCodec) { Debug.Console(2, this, "Adding IHasCameraOff Actions"); cameraOffCodec.CameraIsOffFeedback.OutputChange += (CameraIsOffFeedback_OutputChange); - appServerController.AddAction(MessagePath + "/cameraModeOff", - new Action(cameraOffCodec.CameraOff)); + AddAction("/cameraModeOff", (id, content) => cameraOffCodec.CameraOff()); } } - var selfViewCodec = Codec as IHasCodecSelfView; - if (selfViewCodec != null) + if (Codec is IHasCodecSelfView selfViewCodec) { Debug.Console(2, this, "Adding IHasCodecSelfView Actions"); - appServerController.AddAction(MessagePath + "/cameraSelfView", - new Action(selfViewCodec.SelfViewModeToggle)); + AddAction("/cameraSelfView", (id, content) => selfViewCodec.SelfViewModeToggle()); selfViewCodec.SelfviewIsOnFeedback.OutputChange += new EventHandler(SelfviewIsOnFeedback_OutputChange); } - var layoutsCodec = Codec as IHasCodecLayouts; - if (layoutsCodec != null) + if (Codec is IHasCodecLayouts layoutsCodec) { Debug.Console(2, this, "Adding IHasCodecLayouts Actions"); - appServerController.AddAction(MessagePath + "/cameraRemoteView", - new Action(layoutsCodec.LocalLayoutToggle)); - - appServerController.AddAction(MessagePath + "/cameraLayout", - new Action(layoutsCodec.LocalLayoutToggle)); + AddAction("/cameraRemoteView", (id, content) => layoutsCodec.LocalLayoutToggle()); + AddAction("/cameraLayout", (id, content) => layoutsCodec.LocalLayoutToggle()); } - var pwCodec = Codec as IPasswordPrompt; - if (pwCodec != null) + if (Codec is IPasswordPrompt pwCodec) { Debug.Console(2, this, "Adding IPasswordPrompt Actions"); - appServerController.AddAction(MessagePath + "/password", new Action((s) => pwCodec.SubmitPassword(s))); + AddAction("/password", (id, content) => + { + var msg = content.ToObject>(); + + pwCodec.SubmitPassword(msg.Value); + }); } - var farEndContentStatus = Codec as IHasFarEndContentStatus; - if (farEndContentStatus != null) + if (Codec is IHasFarEndContentStatus farEndContentStatus) { farEndContentStatus.ReceivingContent.OutputChange += (sender, args) => PostReceivingContent(args.BoolValue); @@ -355,13 +340,13 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle Debug.Console(2, this, "Adding Privacy & Standby Actions"); - appServerController.AddAction(MessagePath + "/privacyModeOn", new Action(Codec.PrivacyModeOn)); - appServerController.AddAction(MessagePath + "/privacyModeOff", new Action(Codec.PrivacyModeOff)); - appServerController.AddAction(MessagePath + "/privacyModeToggle", new Action(Codec.PrivacyModeToggle)); - appServerController.AddAction(MessagePath + "/sharingStart", new Action(Codec.StartSharing)); - appServerController.AddAction(MessagePath + "/sharingStop", new Action(Codec.StopSharing)); - appServerController.AddAction(MessagePath + "/standbyOn", new Action(Codec.StandbyActivate)); - appServerController.AddAction(MessagePath + "/standbyOff", new Action(Codec.StandbyDeactivate)); + AddAction("/privacyModeOn", (id, content) => Codec.PrivacyModeOn()); + AddAction("/privacyModeOff", (id, content) => Codec.PrivacyModeOff()); + AddAction("/privacyModeToggle", (id, content) => Codec.PrivacyModeToggle()); + AddAction("/sharingStart", (id, content) => Codec.StartSharing()); + AddAction("/sharingStop", (id, content) => Codec.StopSharing()); + AddAction("/standbyOn", (id, content) => Codec.StandbyActivate()); + AddAction("/standbyOff", (id, content) => Codec.StandbyDeactivate()); } catch (Exception e) { @@ -371,39 +356,45 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle private void SharingSourceFeedback_OutputChange(object sender, FeedbackEventArgs e) { - var state = new VideoCodecBaseStateMessage(); - state.SharingSource = e.StringValue; + var state = new VideoCodecBaseStateMessage + { + SharingSource = e.StringValue + }; PostStatusMessage(state); } private void SharingContentIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) { - var state = new VideoCodecBaseStateMessage(); - state.SharingContentIsOn = e.BoolValue; + var state = new VideoCodecBaseStateMessage + { + SharingContentIsOn = e.BoolValue + }; PostStatusMessage(state); } private void PhonebookSyncState_InitialSyncCompleted(object sender, EventArgs e) { - var state = new VideoCodecBaseStateMessage(); - state.InitialPhonebookSyncComplete = true; + var state = new VideoCodecBaseStateMessage + { + InitialPhonebookSyncComplete = true + }; PostStatusMessage(state); } - void CameraIsOffFeedback_OutputChange(object sender, FeedbackEventArgs e) + private void CameraIsOffFeedback_OutputChange(object sender, FeedbackEventArgs e) { PostCameraMode(); } - void SelfviewIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) + private void SelfviewIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) { PostCameraSelfView(); } - private void presetsCodec_CameraPresetsListHasChanged(object sender, EventArgs e) + private void PresetsCodec_CameraPresetsListHasChanged(object sender, EventArgs e) { PostCameraPresets(); } @@ -414,7 +405,7 @@ private void CameraAutoModeIsOnFeedback_OutputChange(object sender, FeedbackEven } - private void cameraCodec_CameraSelected(object sender, CameraSelectedEventArgs e) + private void CameraCodec_CameraSelected(object sender, CameraSelectedEventArgs e) { MapCameraActions(); PostSelectedCamera(); @@ -425,92 +416,147 @@ private void cameraCodec_CameraSelected(object sender, CameraSelectedEventArgs e /// private void MapCameraActions() { - var cameraCodec = Codec as IHasCameras; - - if (cameraCodec != null && cameraCodec.SelectedCamera != null) + if (Codec is IHasCameras cameraCodec && cameraCodec.SelectedCamera != null) { - AppServerController.RemoveAction(MessagePath + "/cameraUp"); - AppServerController.RemoveAction(MessagePath + "/cameraDown"); - AppServerController.RemoveAction(MessagePath + "/cameraLeft"); - AppServerController.RemoveAction(MessagePath + "/cameraRight"); - AppServerController.RemoveAction(MessagePath + "/cameraZoomIn"); - AppServerController.RemoveAction(MessagePath + "/cameraZoomOut"); - AppServerController.RemoveAction(MessagePath + "/cameraHome"); - - var camera = cameraCodec.SelectedCamera as IHasCameraPtzControl; - if (camera != null) + RemoveAction("/cameraUp"); + RemoveAction("/cameraDown"); + RemoveAction("/cameraLeft"); + RemoveAction("/cameraRight"); + RemoveAction("/cameraZoomIn"); + RemoveAction("/cameraZoomOut"); + RemoveAction("/cameraHome"); + + if (cameraCodec.SelectedCamera is IHasCameraPtzControl camera) { - AppServerController.AddAction(MessagePath + "/cameraUp", new PressAndHoldAction(b => + AddAction("/cameraUp", (id, content) => HandleCameraPressAndHold(content, (b) => { - if (b) camera.TiltUp(); - else camera.TiltStop(); + if (b) + { + camera.TiltUp(); + return; + } + + camera.TiltStop(); })); - AppServerController.AddAction(MessagePath + "/cameraDown", new PressAndHoldAction(b => + + AddAction("/cameraDown", (id, content) => HandleCameraPressAndHold(content, (b) => { - if (b) camera.TiltDown(); - else camera.TiltStop(); + if (b) + { + camera.TiltDown(); + return; + } + + camera.TiltStop(); })); - AppServerController.AddAction(MessagePath + "/cameraLeft", new PressAndHoldAction(b => + + AddAction("/cameraLeft", (id, content) => HandleCameraPressAndHold(content, (b) => { - if (b) camera.PanLeft(); - else camera.PanStop(); + if (b) + { + camera.PanLeft(); + return; + } + + camera.PanStop(); })); - AppServerController.AddAction(MessagePath + "/cameraRight", new PressAndHoldAction(b => + + AddAction("/cameraRight", (id, content) => HandleCameraPressAndHold(content, (b) => { - if (b) camera.PanRight(); - else camera.PanStop(); + if (b) + { + camera.PanRight(); + return; + } + + camera.PanStop(); })); - AppServerController.AddAction(MessagePath + "/cameraZoomIn", new PressAndHoldAction(b => + + AddAction("/cameraZoomIn", (id, content) => HandleCameraPressAndHold(content, (b) => { - if (b) camera.ZoomIn(); - else camera.ZoomStop(); + if (b) + { + camera.ZoomIn(); + return; + } + + camera.ZoomStop(); })); - AppServerController.AddAction(MessagePath + "/cameraZoomOut", new PressAndHoldAction(b => + + AddAction("/cameraZoomOut", (id, content) => HandleCameraPressAndHold(content, (b) => { - if (b) camera.ZoomOut(); - else camera.ZoomStop(); + if (b) + { + camera.ZoomOut(); + return; + } + + camera.ZoomStop(); })); - AppServerController.AddAction(MessagePath + "/cameraHome", new Action(camera.PositionHome)); + AddAction("/cameraHome", (id, content) => camera.PositionHome()); - var focusCamera = cameraCodec as IHasCameraFocusControl; - AppServerController.RemoveAction(MessagePath + "/cameraAutoFocus"); - AppServerController.RemoveAction(MessagePath + "/cameraFocusNear"); - AppServerController.RemoveAction(MessagePath + "/cameraFocusFar"); + RemoveAction("/cameraAutoFocus"); + RemoveAction("/cameraFocusNear"); + RemoveAction("/cameraFocusFar"); - if (focusCamera != null) + if (cameraCodec is IHasCameraFocusControl focusCamera) { - AppServerController.AddAction(MessagePath + "/cameraAutoFocus", - new Action(focusCamera.TriggerAutoFocus)); - AppServerController.AddAction(MessagePath + "/cameraFocusNear", new PressAndHoldAction(b => + AddAction("/cameraAutoFocus", (id, content) => focusCamera.TriggerAutoFocus()); + + AddAction("/cameraFocusNear", (id, content) => HandleCameraPressAndHold(content, (b) => { - if (b) focusCamera.FocusNear(); - else focusCamera.FocusStop(); + if (b) + { + focusCamera.FocusNear(); + return; + } + + focusCamera.FocusStop(); })); - AppServerController.AddAction(MessagePath + "/cameraFocusFar", new PressAndHoldAction(b => + + AddAction("/cameraFocusFar", (id, content) => HandleCameraPressAndHold(content, (b) => { - if (b) focusCamera.FocusFar(); - else focusCamera.FocusStop(); + if (b) + { + focusCamera.FocusFar(); + return; + } + + focusCamera.FocusStop(); })); } } } } + private void HandleCameraPressAndHold(JToken content, Action cameraAction) + { + var state = content.ToObject>(); + + var timerHandler = PressAndHoldHandler.GetPressAndHoldHandler(state.Value); + if (timerHandler == null) + { + return; + } + + timerHandler(state.Value, cameraAction); + + cameraAction(state.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase)); + } + private string GetCameraMode() { string m = ""; - var speakerTrackCodec = Codec as IHasCameraAutoMode; - if (speakerTrackCodec != null) + if (Codec is IHasCameraAutoMode speakerTrackCodec) { m = speakerTrackCodec.CameraAutoModeIsOnFeedback.BoolValue ? eCameraControlMode.Auto.ToString().ToLower() : eCameraControlMode.Manual.ToString().ToLower(); } - var cameraOffCodec = Codec as IHasCameraOff; - if (cameraOffCodec != null) + if (Codec is IHasCameraOff cameraOffCodec) { if (cameraOffCodec.CameraIsOffFeedback.BoolValue) m = eCameraControlMode.Off.ToString().ToLower(); @@ -548,27 +594,13 @@ private CodecActiveCallItem GetCallWithId(string id) return Codec.ActiveCalls.FirstOrDefault(c => c.Id == id); } - /// - /// - /// - /// - private void DirectorySearch(string s) - { - var dirCodec = Codec as IHasDirectory; - if (dirCodec != null) - { - dirCodec.SearchDirectory(s); - } - } - /// /// /// /// private void GetDirectory(string id) { - var dirCodec = Codec as IHasDirectory; - if (dirCodec == null) + if (!(Codec is IHasDirectory dirCodec)) { return; } @@ -580,16 +612,17 @@ private void GetDirectory(string id) /// private void GetDirectoryRoot() { - var dirCodec = Codec as IHasDirectory; - if (dirCodec == null) + if (!(Codec is IHasDirectory dirCodec)) { // do something else? return; } if (!dirCodec.PhonebookSyncState.InitialSyncComplete) { - var state = new VideoCodecBaseStateMessage(); - state.InitialPhonebookSyncComplete = false; + var state = new VideoCodecBaseStateMessage + { + InitialPhonebookSyncComplete = false + }; PostStatusMessage(state); return; @@ -603,8 +636,7 @@ private void GetDirectoryRoot() /// private void GetPreviousDirectory() { - var dirCodec = Codec as IHasDirectory; - if (dirCodec == null) + if (!(Codec is IHasDirectory dirCodec)) { return; } @@ -615,7 +647,7 @@ private void GetPreviousDirectory() /// /// Handler for codec changes /// - private void codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e) + private void Codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e) { SendFullStatus(); } @@ -627,8 +659,10 @@ private void SendIsReady() { var status = new VideoCodecBaseStateMessage(); + var codecType = Codec.GetType(); + status.IsReady = Codec.IsReady; - status.IsZoomRoom = Codec is ZoomRoom; + status.IsZoomRoom = codecType.GetInterface("IHasZoomRoomLayouts") != null; PostStatusMessage(status); } @@ -641,29 +675,29 @@ protected VideoCodecBaseStateMessage GetStatus() { var status = new VideoCodecBaseStateMessage(); - status.CommMonitor = GetCommunicationMonitorState(); - var camerasCodec = Codec as IHasCodecCameras; - if (camerasCodec != null) + if (Codec is IHasCodecCameras camerasCodec) { - status.Cameras = new VideoCodecBaseStateMessage.CameraStatus(); - - status.Cameras.CameraManualIsSupported = true; - status.Cameras.CameraAutoIsSupported = Codec.SupportsCameraAutoMode; - status.Cameras.CameraOffIsSupported = Codec.SupportsCameraOff; - status.Cameras.CameraMode = GetCameraMode(); - status.Cameras.Cameras = camerasCodec.Cameras; - status.Cameras.SelectedCamera = GetSelectedCamera(camerasCodec); + status.Cameras = new VideoCodecBaseStateMessage.CameraStatus + { + CameraManualIsSupported = true, + CameraAutoIsSupported = Codec.SupportsCameraAutoMode, + CameraOffIsSupported = Codec.SupportsCameraOff, + CameraMode = GetCameraMode(), + Cameras = camerasCodec.Cameras, + SelectedCamera = GetSelectedCamera(camerasCodec) + }; } - var directoryCodec = Codec as IHasDirectory; - if (directoryCodec != null) + if (Codec is IHasDirectory directoryCodec) { status.HasDirectory = true; status.HasDirectorySearch = true; status.CurrentDirectory = directoryCodec.CurrentDirectoryResult; } + var codecType = Codec.GetType(); + status.CameraSelfViewIsOn = Codec is IHasCodecSelfView && (Codec as IHasCodecSelfView).SelfviewIsOnFeedback.BoolValue; status.IsInCall = Codec.IsInCall; status.PrivacyModeIsOn = Codec.PrivacyModeIsOnFeedback.BoolValue; @@ -677,11 +711,10 @@ protected VideoCodecBaseStateMessage GetStatus() status.HasRecents = Codec is IHasCallHistory; status.HasCameras = Codec is IHasCameras; status.Presets = GetCurrentPresets(); - status.IsZoomRoom = Codec is ZoomRoom; + status.IsZoomRoom = codecType.GetInterface("IHasZoomRoomLayouts") != null; status.ReceivingContent = Codec is IHasFarEndContentStatus && (Codec as IHasFarEndContentStatus).ReceivingContent.BoolValue; - var meetingInfoCodec = Codec as IHasMeetingInfo; - if (meetingInfoCodec != null) + if (Codec is IHasMeetingInfo meetingInfoCodec) { status.MeetingInfo = meetingInfoCodec.MeetingInfo; } @@ -703,18 +736,20 @@ protected virtual void SendFullStatus() private void PostReceivingContent(bool receivingContent) { - var state = new VideoCodecBaseStateMessage(); - state.ReceivingContent = receivingContent; + var state = new VideoCodecBaseStateMessage + { + ReceivingContent = receivingContent + }; PostStatusMessage(state); } private void PostCameraSelfView() { - var status = new VideoCodecBaseStateMessage(); - - status.CameraSelfViewIsOn = Codec is IHasCodecSelfView - ? (Codec as IHasCodecSelfView).SelfviewIsOnFeedback.BoolValue - : false; + var status = new VideoCodecBaseStateMessage + { + CameraSelfViewIsOn = Codec is IHasCodecSelfView + && (Codec as IHasCodecSelfView).SelfviewIsOnFeedback.BoolValue + }; PostStatusMessage(status); } @@ -724,9 +759,10 @@ private void PostCameraSelfView() /// private void PostCameraMode() { - var status = new VideoCodecBaseStateMessage(); - - status.CameraMode = GetCameraMode(); + var status = new VideoCodecBaseStateMessage + { + CameraMode = GetCameraMode() + }; PostStatusMessage(status); } @@ -735,25 +771,27 @@ private void PostSelectedCamera() { var camerasCodec = Codec as IHasCodecCameras; - var status = new VideoCodecBaseStateMessage(); - - status.Cameras = new VideoCodecBaseStateMessage.CameraStatus() { SelectedCamera = GetSelectedCamera(camerasCodec) }; - status.Presets = GetCurrentPresets(); + var status = new VideoCodecBaseStateMessage + { + Cameras = new VideoCodecBaseStateMessage.CameraStatus() { SelectedCamera = GetSelectedCamera(camerasCodec) }, + Presets = GetCurrentPresets() + }; PostStatusMessage(status); } private void PostCameraPresets() { - var status = new VideoCodecBaseStateMessage(); - - status.Presets = GetCurrentPresets(); + var status = new VideoCodecBaseStateMessage + { + Presets = GetCurrentPresets() + }; PostStatusMessage(status); } - private VideoCodecBaseStateMessage.CameraStatus.Camera GetSelectedCamera(IHasCodecCameras camerasCodec) + private Camera GetSelectedCamera(IHasCodecCameras camerasCodec) { - var camera = new VideoCodecBaseStateMessage.CameraStatus.Camera(); + var camera = new Camera(); if (camerasCodec.SelectedCameraFeedback != null) camera.Key = camerasCodec.SelectedCameraFeedback.StringValue; @@ -761,7 +799,7 @@ private VideoCodecBaseStateMessage.CameraStatus.Camera GetSelectedCamera(IHasCod { camera.Name = camerasCodec.SelectedCamera.Name; - camera.Capabilities = new VideoCodecBaseStateMessage.CameraStatus.Camera.CameraCapabilities() + camera.Capabilities = new Camera.CameraCapabilities() { CanPan = camerasCodec.SelectedCamera.CanPan, CanTilt = camerasCodec.SelectedCamera.CanTilt, @@ -773,8 +811,8 @@ private VideoCodecBaseStateMessage.CameraStatus.Camera GetSelectedCamera(IHasCod if (camerasCodec.ControllingFarEndCameraFeedback != null) camera.IsFarEnd = camerasCodec.ControllingFarEndCameraFeedback.BoolValue; - - return camera; + + return camera; } private List GetCurrentPresets() @@ -799,7 +837,7 @@ public class VideoCodecBaseStateMessage : DeviceStateMessageBase { [JsonProperty("calls", NullValueHandling = NullValueHandling.Ignore)] - public List Calls {get; set;} + public List Calls { get; set; } [JsonProperty("cameraMode", NullValueHandling = NullValueHandling.Ignore)] public string CameraMode { get; set; } @@ -888,7 +926,7 @@ public class VideoCodecBaseStateMessage : DeviceStateMessageBase [JsonProperty("supportsAdHocMeeting", NullValueHandling = NullValueHandling.Ignore)] public bool? SupportsAdHocMeeting { get; set; } - public class CameraStatus + public class CameraStatus { [JsonProperty("cameraManualSupported", NullValueHandling = NullValueHandling.Ignore)] public bool? CameraManualIsSupported { get; set; } @@ -943,7 +981,7 @@ public class CameraCapabilities } - public class VideoCodecBaseEventMessage: DeviceEventMessageBase + public class VideoCodecBaseEventMessage : DeviceEventMessageBase { } diff --git a/3-series/MobileControlConfig.cs b/3-series/MobileControlConfig.cs index c08659e..937a86a 100644 --- a/3-series/MobileControlConfig.cs +++ b/3-series/MobileControlConfig.cs @@ -1,8 +1,6 @@ -using System.Collections.Generic; -using System.Security.Policy; -using Crestron.SimplSharp.Ssh.Security; -using Newtonsoft.Json; +using Newtonsoft.Json; using Newtonsoft.Json.Converters; +using System.Collections.Generic; namespace PepperDash.Essentials { @@ -22,7 +20,7 @@ public class MobileControlConfig public MobileControlDirectServerPropertiesConfig DirectServer { get; set; } [JsonProperty("applicationConfig")] - public MobileControlApplicationConfig ApplicationConfig{get; set;} + public MobileControlApplicationConfig ApplicationConfig { get; set; } [JsonProperty("enableApiServer")] public bool EnableApiServer { get; set; } @@ -37,7 +35,7 @@ public MobileControlConfig() #if SERIES4 EnableApiServer = true; // default to true - ApplicationConfig = null; + ApplicationConfig = null; #endif } } @@ -69,7 +67,7 @@ public class MobileControlLoggingConfig [JsonProperty("port")] public int Port { get; set; } - + } public class MobileControlRoomBridgePropertiesConfig diff --git a/3-series/MobileControlEssentialsConfig.cs b/3-series/MobileControlEssentialsConfig.cs index d40f299..aab9b53 100644 --- a/3-series/MobileControlEssentialsConfig.cs +++ b/3-series/MobileControlEssentialsConfig.cs @@ -1,10 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; +using Newtonsoft.Json; using PepperDash.Essentials.Core.Config; -using Newtonsoft.Json; namespace PepperDash.Essentials @@ -18,7 +13,7 @@ public class MobileControlEssentialsConfig : EssentialsConfig public MobileControlRuntimeInfo RuntimeInfo { get; set; } public MobileControlEssentialsConfig(EssentialsConfig config) - :base() + : base() { // TODO: Consider using Reflection to iterate properties this.Devices = config.Devices; diff --git a/3-series/MobileControlFactory.cs b/3-series/MobileControlFactory.cs index a6d8632..ff535f6 100644 --- a/3-series/MobileControlFactory.cs +++ b/3-series/MobileControlFactory.cs @@ -1,11 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using PepperDash.Core; +using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Room.MobileControl; +using System; +using System.Collections.Generic; +using System.Linq; namespace PepperDash.Essentials @@ -15,7 +14,7 @@ public class MobileControlFactory : EssentialsPluginDeviceFactory {"appserver", "mobilecontrol", "webserver" }; + TypeNames = new List { "appserver", "mobilecontrol", "webserver" }; } public override EssentialsDevice BuildDevice(DeviceConfig dc) @@ -33,12 +32,12 @@ public override EssentialsDevice BuildDevice(DeviceConfig dc) } } - public class MobileControlSimplFactory : EssentialsPluginDeviceFactory + public class MobileControlSimplFactory : EssentialsPluginDeviceFactory { public MobileControlSimplFactory() { MinimumEssentialsFrameworkVersion = "1.12.5"; - TypeNames = new List {"mobilecontrolbridge-ddvc01", "mobilecontrolbridge-simpl"}; + TypeNames = new List { "mobilecontrolbridge-ddvc01", "mobilecontrolbridge-simpl" }; } public override EssentialsDevice BuildDevice(DeviceConfig dc) @@ -57,8 +56,11 @@ public override EssentialsDevice BuildDevice(DeviceConfig dc) return; } Debug.Console(0, bridge, "Linking to parent controller"); - bridge.AddParent(parent); - parent.AddBridge(bridge); + + /*bridge.AddParent(parent); + parent.AddBridge(bridge);*/ + + parent.AddDeviceMessenger(bridge); }); return bridge; diff --git a/3-series/MobileControlSimplDeviceBridge.cs b/3-series/MobileControlSimplDeviceBridge.cs index 934f54e..f1ebf62 100644 --- a/3-series/MobileControlSimplDeviceBridge.cs +++ b/3-series/MobileControlSimplDeviceBridge.cs @@ -1,7 +1,7 @@ -using System; -using Crestron.SimplSharpPro.EthernetCommunication; +using Crestron.SimplSharpPro.EthernetCommunication; using PepperDash.Core; using PepperDash.Essentials.Core; +using System; namespace PepperDash.Essentials.Room.MobileControl { diff --git a/3-series/MobileControlSystemController.cs b/3-series/MobileControlSystemController.cs index ff688e1..f67ba96 100644 --- a/3-series/MobileControlSystemController.cs +++ b/3-series/MobileControlSystemController.cs @@ -1,49 +1,63 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; -using Crestron.SimplSharp; +using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.Net.Http; -using Crestron.SimplSharp.Net.Https; using Crestron.SimplSharp.Reflection; +using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Core.CrestronIO; +using PepperDash.Essentials.Core.DeviceInfo; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Core.Lighting; using PepperDash.Essentials.Core.Monitoring; -using PepperDash.Essentials.Core.Presets; using PepperDash.Essentials.Core.Queues; -using PepperDash.Essentials.Room.Config; +using PepperDash.Essentials.Core.Routing; +using PepperDash.Essentials.Core.Shades; +using PepperDash.Essentials.Core.Web; +using PepperDash.Essentials.Devices.Common.AudioCodec; +using PepperDash.Essentials.Devices.Common.Cameras; +using PepperDash.Essentials.Devices.Common.SoftCodec; +using PepperDash.Essentials.Devices.Common.TouchPanel; +using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Room.MobileControl; -using PepperDash.Essentials.Devices.Common.Codec; +using PepperDash.Essentials.Services; +using PepperDash.Essentials.WebApiHandlers; +using Serilog.Events; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; using WebSocketSharp; +using DisplayBase = PepperDash.Essentials.Devices.Common.Displays.DisplayBase; +using TwoWayDisplayBase = PepperDash.Essentials.Devices.Common.Displays.TwoWayDisplayBase; #if SERIES4 -using PepperDash.Essentials.AppServer; #endif namespace PepperDash.Essentials { - public class MobileControlSystemController : EssentialsDevice, IMobileControl3 + public class MobileControlSystemController : EssentialsDevice, IMobileControl { - //WebSocketClient WSClient; - + private bool _initialized = false; private const long ServerReconnectInterval = 5000; private const long PingInterval = 25000; - private const long ButtonHeartbeatInterval = 1000; - private readonly Dictionary _actionDictionary = - new Dictionary(StringComparer.InvariantCultureIgnoreCase); + private readonly Dictionary> _actionDictionary = + new Dictionary>(StringComparer.InvariantCultureIgnoreCase); + + public Dictionary> ActionDictionary => _actionDictionary; - private readonly Dictionary _pushedActions = new Dictionary(); private readonly GenericQueue _receiveQueue; private readonly List _roomBridges = new List(); #if SERIES4 - private readonly Dictionary _deviceMessengers = new Dictionary(); + private readonly Dictionary _messengers = new Dictionary(); + + private readonly Dictionary _defaultMessengers = new Dictionary(); #else private readonly Dictionary _deviceMessengers = new Dictionary(); #endif @@ -55,13 +69,21 @@ public class MobileControlSystemController : EssentialsDevice, IMobileControl3 private bool _disableReconnect; private WebSocket _wsClient2; + public MobileControlApiService ApiService { get; private set; } + + public List RoomBridges => _roomBridges; + #if SERIES4 - private MobileControlWebsocketServer _directServer; + private readonly MobileControlWebsocketServer _directServer; + + public MobileControlWebsocketServer DirectServer => _directServer; #endif private readonly CCriticalSection _wsCriticalSection = new CCriticalSection(); public string SystemUrl; //set only from SIMPL Bridge! + public bool Connected => _wsClient2 != null && _wsClient2.IsAlive; + public string SystemUuid { get @@ -78,7 +100,7 @@ public string SystemUuid if (!string.IsNullOrEmpty(SystemUrl)) { Debug.Console(0, this, Debug.ErrorLogLevel.Error, "No system_url value defined in config or SIMPL Bridge. Unable to connect to Mobile Control."); - return String.Empty; + return string.Empty; } var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/#.*"); @@ -117,14 +139,9 @@ private set private DateTime _lastAckMessage; - private CTimer _pingTimer; - - /// - /// Prevents post operations from stomping on each other and getting lost - /// - private CEvent _postLockEvent = new CEvent(true, true); + public DateTime LastAckMessage => _lastAckMessage; - private CEvent _registerLockEvent = new CEvent(true, true); + private CTimer _pingTimer; private CTimer _serverReconnectTimer; private LogLevel _wsLogLevel = LogLevel.Error; @@ -163,8 +180,438 @@ public MobileControlSystemController(string key, string name, MobileControlConfi Host = "https://" + Host; } + ApiService = new MobileControlApiService(Host); + Debug.Console(0, this, "Mobile UI controller initializing for server:{0}", config.ServerUrl); + if (Global.Platform == eDevicePlatform.Appliance) + { + AddConsoleCommands(); + } + + AddPreActivationAction(() => LinkSystemMonitorToAppServer()); + + AddPreActivationAction(() => SetupDefaultDeviceMessengers()); + + AddPreActivationAction(() => SetupDefaultRoomMessengers()); + + AddPreActivationAction(() => AddWebApiPaths()); + + CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; + + ApiOnlineAndAuthorized = new BoolFeedback(() => + { + if (_wsClient2 == null) + return false; + + return _wsClient2.IsAlive && IsAuthorized; + }); + } + + private void SetupDefaultRoomMessengers() + { + foreach (var room in DeviceManager.AllDevices.OfType()) + { + var messenger = new MobileControlEssentialsRoomBridge(room); + + _roomBridges.Add(messenger); + + AddDefaultDeviceMessenger(messenger); + + Debug.Console(2, this, "Attempting to set up room messengers for room: {0}", room.Key); + + if (room is IRoomEventSchedule) + { + var scheduleMessenger = new RoomEventScheduleMessenger($"{room.Key}-schedule-{Key}", + + string.Format("/room/{0}", room.Key), room as IRoomEventSchedule); + + AddDefaultDeviceMessenger(scheduleMessenger); + } + + if (room is ITechPassword) + { + var techPasswordMessenger = new ITechPasswordMessenger($"{room.Key}-techPassword-{Key}", + string.Format("/room/{0}", room.Key), room as ITechPassword); + + AddDefaultDeviceMessenger(techPasswordMessenger); + } + + if (room is IShutdownPromptTimer) + { + var shutdownPromptTimerMessenger = new IShutdownPromptTimerMessenger($"{room.Key}-shutdownPromptTimer-{Key}", + string.Format("/room/{0}", room.Key), room as IShutdownPromptTimer); + + AddDefaultDeviceMessenger(shutdownPromptTimerMessenger); + } + } + } + + /// + /// Set up the messengers for each device type + /// + private void SetupDefaultDeviceMessengers() + { + bool messengerAdded = false; + foreach (var device in DeviceManager.AllDevices.Where((d) => !(d is IEssentialsRoom)).Cast()) + { + Debug.Console(2, this, "Attempting to set up device messengers for device: {0}", device.Key); + + + if (device is ICommunicationMonitor) + { + Debug.Console(2, this, "Adding CommunicationMonitorMessenger for device: {0}", device.Key); + var commMessenger = new ICommunicationMonitorMessenger($"{device.Key}-commMonitor-{Key}", + string.Format("/device/{0}", device.Key), device as ICommunicationMonitor); + AddDefaultDeviceMessenger(commMessenger); + messengerAdded = true; + } + + if (device is CameraBase) + { + Debug.Console(2, this, "Adding CameraBaseMessenger for device: {0}", device.Key); + + var cameraMessenger = new CameraBaseMessenger($"{device.Key}-cameraBase-{Key}", device as CameraBase, + $"/device/{device.Key}"); + + AddDefaultDeviceMessenger(cameraMessenger); + + messengerAdded = true; + } + + if (device is BlueJeansPc) + { + Debug.Console(2, this, "Adding IRunRouteActionMessnger for device: {0}", device.Key); + + var routeMessenger = new RunRouteActionMessenger($"{device.Key}-runRouteAction-{Key}", device as BlueJeansPc, + $"/device/{device.Key}"); + + AddDefaultDeviceMessenger(routeMessenger); + + messengerAdded = true; + } + + if (device is ITvPresetsProvider) + { + var presetsDevice = device as ITvPresetsProvider; + + if (presetsDevice.TvPresets == null) + { + Debug.Console(2, this, "TvPresets is null for device: '{0}'. Skipping DevicePresetsModelMessenger", device.Key); + } + else + { + Debug.Console(2, this, "Adding ITvPresetsProvider for device: {0}", device.Key); + + var presetsMessenger = new DevicePresetsModelMessenger($"{device.Key}-presets-{Key}", $"/device/{device.Key}/presets", + presetsDevice); + + AddDefaultDeviceMessenger(presetsMessenger); + + messengerAdded = true; + } + } + + if (device is DisplayBase) + { + + Debug.Console(2, this, "Adding actions for device: {0}", device.Key); + + var dbMessenger = new DisplayBaseMessenger($"{device.Key}-displayBase-{Key}", $"/device/{device.Key}", device as DisplayBase); + + AddDefaultDeviceMessenger(dbMessenger); + + messengerAdded = true; + } + + if (device is Core.DisplayBase) + { + Debug.Console(2, this, "Adding actions for device: {0}", device.Key); + + var dbMessenger = new CoreDisplayBaseMessenger($"{device.Key}-displayBase-{Key}", $"/device/{device.Key}", device as Core.DisplayBase); + AddDefaultDeviceMessenger(dbMessenger); + + messengerAdded = true; + } + + if (device is TwoWayDisplayBase) + { + var display = device as TwoWayDisplayBase; + Debug.Console(2, this, "Adding TwoWayDisplayBase for device: {0}", device.Key); + var twoWayDisplayMessenger = new TwoWayDisplayBaseMessenger($"{device.Key}-twoWayDisplay-{Key}", + string.Format("/device/{0}", device.Key), display); + AddDefaultDeviceMessenger(twoWayDisplayMessenger); + + messengerAdded = true; + } + + if (device is Core.TwoWayDisplayBase) + { + var display = device as Core.TwoWayDisplayBase; + Debug.Console(2, this, "Adding TwoWayDisplayBase for device: {0}", device.Key); + var twoWayDisplayMessenger = new CoreTwoWayDisplayBaseMessenger($"{device.Key}-twoWayDisplay-{Key}", + string.Format("/device/{0}", device.Key), display); + AddDefaultDeviceMessenger(twoWayDisplayMessenger); + + messengerAdded = true; + } + + if (device is IBasicVolumeWithFeedback) + { + var deviceKey = device.Key; + var volControlDevice = device as IBasicVolumeWithFeedback; + Debug.Console(2, this, "Adding IBasicVolumeControlWithFeedback for device: {0}", deviceKey); + var messenger = new DeviceVolumeMessenger($"{device.Key}-volume-{Key}", + string.Format("/device/{0}", deviceKey), volControlDevice); + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is ILightingScenes) + { + var deviceKey = device.Key; + var lightingDevice = device as ILightingScenes; + Debug.Console(2, this, "Adding LightingBaseMessenger for device: {0}", deviceKey); + var messenger = new ILightingScenesMessenger($"{device.Key}-lighting-{Key}", + lightingDevice, string.Format("/device/{0}", deviceKey)); + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IShadesOpenCloseStop) + { + var deviceKey = device.Key; + var shadeDevice = device as IShadesOpenCloseStop; + Debug.Console(2, this, "Adding ShadeBaseMessenger for device: {0}", deviceKey); + var messenger = new IShadesOpenCloseStopMessenger($"{device.Key}-shades-{Key}", + shadeDevice, string.Format("/device/{0}", deviceKey)); + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if(device is VideoCodecBase codec) + { + Debug.Console(2, this, $"Adding VideoCodecBaseMessenger for device: {codec.Key}"); + + var messenger = new VideoCodecBaseMessenger($"{codec.Key}-videoCodec-{Key}", codec, $"/device/{codec.Key}"); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if(device is AudioCodecBase audioCodec) { + Debug.Console(2, this, $"Adding AudioCodecBaseMessenger for device: {audioCodec.Key}"); + + var messenger = new AudioCodecBaseMessenger($"{audioCodec.Key}-audioCodec-{Key}", audioCodec, $"/device/{audioCodec.Key}"); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if(device is ISetTopBoxControls) + { + Debug.Console(2, this, $"Adding ISetTopBoxControlMessenger for device: {device.Key}"); + + var messenger = new ISetTopBoxControlsMessenger($"{device.Key}-stb-{Key}", $"/device/{device.Key}", device); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IChannel) + { + Debug.Console(2, this, $"Adding IChannelMessenger for device: {device.Key}"); + + var messenger = new IChannelMessenger($"{device.Key}-channel-{Key}", $"/device/{device.Key}", device); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IColor) + { + Debug.Console(2, this, $"Adding IColorMessenger for device: {device.Key}"); + + var messenger = new IColorMessenger($"{device.Key}-color-{Key}", $"/device/{device.Key}", device); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IDPad) + { + Debug.Console(2, this, $"Adding IDPadMessenger for device: {device.Key}"); + + var messenger = new IDPadMessenger($"{device.Key}-dPad-{Key}", $"/device/{device.Key}", device); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is INumericKeypad) + { + Debug.Console(2, this, $"Adding INumericKeyapdMessenger for device: {device.Key}"); + + var messenger = new INumericKeypadMessenger($"{device.Key}-numericKeypad-{Key}", $"/device/{device.Key}", device); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IHasPowerControl) + { + Debug.Console(2, this, $"Adding IHasPowerControlMessenger for device: {device.Key}"); + + var messenger = new IHasPowerMessenger($"{device.Key}-powerControl-{Key}", $"/device/{device.Key}", device); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IHasPowerControlWithFeedback powerControl) + { + var deviceKey = device.Key; + Debug.Console(2, this, "Adding IHasPowerControlWithFeedbackMessenger for device: {0}", deviceKey); + var messenger = new IHasPowerControlWithFeedbackMessenger($"{device.Key}-powerFeedback-{Key}", + string.Format("/device/{0}", deviceKey), powerControl); + AddDefaultDeviceMessenger(messenger); + messengerAdded = true; + } + + if (device is ITransport) + { + Debug.Console(2, this, $"Adding ITransportMessenger for device: {device.Key}"); + + var messenger = new IChannelMessenger($"{device.Key}-transport-{Key}", $"/device/{device.Key}", device); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if(device is IHasCurrentSourceInfoChange) + { + Debug.Console(2, this, $"Adding IHasCurrentSourceInfoMessenger for device: {device.Key}"); + + var messenger = new IHasCurrentSourceInfoMessenger($"{device.Key}-currentSource-{Key}", $"/device/{device.Key}", device as IHasCurrentSourceInfoChange); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is ISwitchedOutput) + { + Debug.Console(2, this, $"Adding ISwitchedOutputMessenger for device: {device.Key}"); + + var messenger = new ISwitchedOutputMessenger($"{device.Key}-switchedOutput-{Key}", device as ISwitchedOutput, $"/device/{device.Key}"); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if(device is IDeviceInfoProvider provider) + { + Debug.Console(2, this, $"Adding IHasDeviceInfoMessenger for device: {device.Key}"); + + var messenger = new DeviceInfoMessenger($"{device.Key}-deviceInfo-{Key}", $"/device/{device.Key}", provider); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if(device is ILevelControls levelControls) + { + Debug.Console(2, this, $"Adding LevelControlsMessenger for device: {device.Key}"); + + var messenger = new ILevelControlsMessenger($"{device.Key}-levelControls-{Key}", $"/device/{device.Key}", levelControls); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + // This will work if TKey and TSelector are both string types. + // Otherwise plugin device needs to instantiate ISelectableItemsMessenger and add it to the controller. + if(device is IHasInputs inputs) + { + Debug.Console(2, this, $"Adding InputsMessenger for device: {device.Key}"); + + var messenger = new ISelectableItemsMessenger($"{device.Key}-inputs-{Key}", $"/device/{device.Key}", inputs.Inputs, "inputs"); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if(device is IMatrixRouting matrix) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Adding IMatrixRoutingMessenger for device: {key}", this, device.Key); + + var messenger = new IMatrixRoutingMessenger($"{device.Key}-matrixRouting", $"/device/{device.Key}", matrix); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (!(device is EssentialsDevice genericDevice) || messengerAdded) + { + continue; + } + + Debug.Console(2, this, "Adding GenericMessenger for device: {0}", genericDevice.Key); + AddDefaultDeviceMessenger(new GenericMessenger(genericDevice.Key + "-" + Key + "-generic", genericDevice, string.Format("/device/{0}", genericDevice.Key))); + } + } + + private void AddWebApiPaths() + { + var apiServer = DeviceManager.AllDevices.OfType().FirstOrDefault(d => d.Key == "essentialsWebApi"); + + if (apiServer == null) + { + Debug.Console(0, this, "No API Server available"); + return; + } + + var routes = new List + { + new HttpCwsRoute($"device/{Key}/authorize") + { + Name = "MobileControlAuthorize", + RouteHandler = new MobileAuthRequestHandler(this) + }, + new HttpCwsRoute($"device/{Key}/info") + { + Name = "MobileControlInformation", + RouteHandler = new MobileInfoHandler(this) + }, + new HttpCwsRoute($"device/{Key}/actionPaths") + { + Name = "MobileControlActionPaths", + RouteHandler = new ActionPathsHandler(this) + } + }; + + apiServer.AddRoute(routes); + } + + private void AddConsoleCommands() + { CrestronConsole.AddNewConsoleCommand(AuthorizeSystem, "mobileauth", "Authorizes system to talk to Mobile Control server", ConsoleAccessLevelEnum.AccessOperator); @@ -207,36 +654,22 @@ public MobileControlSystemController(string key, string name, MobileControlConfi CrestronConsole.AddNewConsoleCommand(SetWebsocketDebugLevel, "mobilewsdebug", "Set Websocket debug level", ConsoleAccessLevelEnum.AccessProgrammer); - - CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; - - // Config Messenger - //var cmKey = Key + "-config"; - //ConfigMessenger = new ConfigMessenger(cmKey, "/config"); - //ConfigMessenger.RegisterWithAppServer(this); - - ApiOnlineAndAuthorized = new BoolFeedback(() => { - if(_wsClient2 == null) - return false; - - return _wsClient2.IsAlive && IsAuthorized; - }); } public MobileControlConfig Config { get; private set; } public string Host { get; private set; } - //public ConfigMessenger ConfigMessenger { get; private set; } - + + public string ClientAppUrl => Config.ClientAppUrl; private void RoomCombinerOnRoomCombinationScenarioChanged(object sender, EventArgs eventArgs) { - SendMessageObject(new {type = "/system/roomCombinationChanged"}); + SendMessageObject(new MobileControlMessage { Type = "/system/roomCombinationChanged" }); } public bool CheckForDeviceMessenger(string key) { - return _deviceMessengers.ContainsKey(key); + return _messengers.ContainsKey(key); } #if SERIES4 @@ -245,49 +678,102 @@ public void AddDeviceMessenger(IMobileControlMessenger messenger) public void AddDeviceMessenger(MessengerBase messenger) #endif { - if (_deviceMessengers.ContainsKey(messenger.Key)) + if (_messengers.ContainsKey(messenger.Key)) { Debug.Console(1, this, "Messenger with key {0} already added", messenger.Key); return; } - if(_deviceMessengers.Any((kv) => kv.Value.MessagePath.Equals(messenger.MessagePath, StringComparison.InvariantCulture))) { - Debug.Console(1, this, "Messenger with path {0} alread added", messenger.MessagePath); - return; + if (messenger is IDelayedConfiguration simplMessenger) + { + simplMessenger.ConfigurationIsReady += Bridge_ConfigurationIsReady; + } + + if (messenger is MobileControlBridgeBase roomBridge) + { + _roomBridges.Add(roomBridge); } Debug.Console(2, this, "Adding messenger with key {0} for path {1}", messenger.Key, messenger.MessagePath); - _deviceMessengers.Add(messenger.Key, messenger); + _messengers.Add(messenger.Key, messenger); messenger.RegisterWithAppServer(this); } - private void CreateMobileControlRoomBridges() + private void AddDefaultDeviceMessenger(IMobileControlMessenger messenger) { - if (Config.RoomBridges.Count == 0) + if (_defaultMessengers.ContainsKey(messenger.Key)) { - Debug.Console(0, this, "No Room bridges configured explicitly. Bridges will be created for each configured room."); + Debug.Console(1, this, "Default messenger with key {0} already added", messenger.Key); return; } - foreach (var bridge in Config.RoomBridges.Select(bridgeConfig => - new MobileControlEssentialsRoomBridge(bridgeConfig.Key, bridgeConfig.RoomKey, DeviceManager.GetDeviceForKey(bridgeConfig.RoomKey) as Device))) + if (messenger is IDelayedConfiguration simplMessenger) { - AddBridgePostActivationAction(bridge); - DeviceManager.AddDevice(bridge); + simplMessenger.ConfigurationIsReady += Bridge_ConfigurationIsReady; } + Debug.Console(2, this, "Adding default messenger with key {0} for path {1}", messenger.Key, messenger.MessagePath); + + _defaultMessengers.Add(messenger.Key, messenger); + + if (_initialized) + { + RegisterMessengerWithServer(messenger); + } } - #region IMobileControl Members + private void RegisterMessengerWithServer(IMobileControlMessenger messenger) + { + Debug.Console(2, this, "Registering messenger with key {0} for path {1}", messenger.Key, messenger.MessagePath); + + messenger.RegisterWithAppServer(this); + } - public void CreateMobileControlRoomBridge(EssentialsRoomBase room, IMobileControl parent) + public override void Initialize() { - var bridge = new MobileControlEssentialsRoomBridge(room); - AddBridgePostActivationAction(bridge); - DeviceManager.AddDevice(bridge); + foreach (var messenger in _messengers) + { + try + { + RegisterMessengerWithServer(messenger.Value); + } + catch (Exception ex) + { + Debug.Console(0, this, $"Exception registering paths for {messenger.Key}: {ex.Message}"); + Debug.Console(2, this, $"Exception registering paths for {messenger.Key}: {ex.StackTrace}"); + continue; + } + } + + foreach (var messenger in _defaultMessengers) + { + try + { + RegisterMessengerWithServer(messenger.Value); + } + catch (Exception ex) + { + Debug.Console(0, this, $"Exception registering paths for {messenger.Key}: {ex.Message}"); + Debug.Console(2, this, $"Exception registering paths for {messenger.Key}: {ex.StackTrace}"); + continue; + } + } + + var simplMessengers = _messengers.OfType().ToList(); + + if (simplMessengers.Count > 0) + { + return; + } + + _initialized = true; + + RegisterSystemToServer(); } + #region IMobileControl Members + public static IMobileControl GetAppServer() { try @@ -313,7 +799,7 @@ private bool CreateWebsocket() _wsClient2 = null; } - if (String.IsNullOrEmpty(SystemUuid)) + if (string.IsNullOrEmpty(SystemUuid)) { Debug.Console(0, this, Debug.ErrorLogLevel.Error, "System UUID not defined. Unable to connect to Mobile Control"); return false; @@ -331,6 +817,8 @@ private bool CreateWebsocket() } }; + _wsClient2.SslConfiguration.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls12; + _wsClient2.OnMessage += HandleMessage; _wsClient2.OnOpen += HandleOpen; _wsClient2.OnError += HandleError; @@ -348,29 +836,23 @@ public void LinkSystemMonitorToAppServer() return; } - var sysMon = DeviceManager.GetDeviceForKey("systemMonitor") as SystemMonitorController; - - var appServer = GetAppServer() as MobileControlSystemController; - - if (sysMon == null || appServer == null) + if (!(DeviceManager.GetDeviceForKey("systemMonitor") is SystemMonitorController sysMon)) { return; } - var key = sysMon.Key + "-" + appServer.Key; + var key = sysMon.Key + "-" + Key; var messenger = new SystemMonitorMessenger(key, sysMon, "/device/systemMonitor"); - messenger.RegisterWithAppServer(appServer); - - DeviceManager.AddDevice(messenger); + AddDeviceMessenger(messenger); } - public void CreateMobileControlRoomBridge(IEssentialsRoom room, IMobileControl parent) - { - var bridge = new MobileControlEssentialsRoomBridge(room); - AddBridgePostActivationAction(bridge); - DeviceManager.AddDevice(bridge); - } + /* public void CreateMobileControlRoomBridge(IEssentialsRoom room, IMobileControl parent) + { + var bridge = new MobileControlEssentialsRoomBridge(room); + AddBridgePostActivationAction(bridge); + DeviceManager.AddDevice(bridge); + } */ #endregion @@ -382,7 +864,7 @@ private void SetWebsocketDebugLevel(string cmdparameters) return; // Web socket log level not currently allowed in series4 } - if (String.IsNullOrEmpty(cmdparameters)) + if (string.IsNullOrEmpty(cmdparameters)) { Debug.Console(0, this, "Current Websocket debug level: {0}", _wsLogLevel); return; @@ -396,7 +878,7 @@ private void SetWebsocketDebugLevel(string cmdparameters) try { - var debugLevel = (LogLevel) Enum.Parse(typeof (LogLevel), cmdparameters, true); + var debugLevel = (LogLevel)Enum.Parse(typeof(LogLevel), cmdparameters, true); _wsLogLevel = debugLevel; @@ -404,48 +886,26 @@ private void SetWebsocketDebugLevel(string cmdparameters) { _wsClient2.Log.Level = _wsLogLevel; } - + Debug.Console(0, this, "Websocket log level set to {0}", debugLevel); } catch { - Debug.Console(0, this, "{0} is not a valid debug level. Valid options are: {1}, {2}, {3}, {4}, {5}, {6}",cmdparameters, + Debug.Console(0, this, "{0} is not a valid debug level. Valid options are: {1}, {2}, {3}, {4}, {5}, {6}", cmdparameters, LogLevel.Trace, LogLevel.Debug, LogLevel.Info, LogLevel.Warn, LogLevel.Error, LogLevel.Fatal); } } - private void AddBridgePostActivationAction(MobileControlBridgeBase bridge) - { - bridge.AddPostActivationAction(() => - { - Debug.Console(0, bridge, "Linking to parent controller"); - bridge.AddParent(this); - AddBridge(bridge); - }); - } - - /// - /// If config rooms is empty or null then go - /// - /// - public override bool CustomActivate() - { - if (ConfigReader.ConfigObject.Rooms != null && ConfigReader.ConfigObject.Rooms.Count != 0) - { - return base.CustomActivate(); - } - - if (_roomBridges.OfType().ToList().Count > 0) - { - return base.CustomActivate(); - } - - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Config contains no rooms. Registering with Server."); - RegisterSystemToServer(); - - return base.CustomActivate(); - } + /* private void AddBridgePostActivationAction(MobileControlBridgeBase bridge) + { + bridge.AddPostActivationAction(() => + { + Debug.Console(0, bridge, "Linking to parent controller"); + bridge.AddParent(this); + AddBridge(bridge); + }); + }*/ /// /// Sends message to server to indicate the system is shutting down @@ -466,12 +926,31 @@ private void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventTy public void PrintActionDictionaryPaths(object o) { - Debug.Console(0, this, "ActionDictionary Contents:"); + CrestronConsole.ConsoleCommandResponse("ActionDictionary Contents:\r\n"); + + foreach(var (messengerKey, actionPath) in GetActionDictionaryPaths()) + { + CrestronConsole.ConsoleCommandResponse($"<{messengerKey}> {actionPath}\r\n"); + } + } + + public List<(string, string)> GetActionDictionaryPaths() + { + var paths = new List<(string, string)>(); foreach (var item in _actionDictionary) { - Debug.Console(0, this, "{0}", item.Key); + var messengers = item.Value.Select(a => a.Messenger).Cast(); + foreach (var messenger in messengers) + { + foreach (var actionPath in messenger.GetActionPaths()) + { + paths.Add((messenger.Key, $"{item.Key}{actionPath}")); + } + } } + + return paths; } /// @@ -479,17 +958,27 @@ public void PrintActionDictionaryPaths(object o) /// /// The path of the API command /// The action to be triggered by the commmand - public void AddAction(string key, object action) + public void AddAction(T messenger, Action action) where T:IMobileControlMessenger { - if (!_actionDictionary.ContainsKey(key)) + if (_actionDictionary.TryGetValue(messenger.MessagePath, out List actionList)) { - _actionDictionary.Add(key, action); + + if(actionList.Any(a => a.Messenger.GetType() == messenger.GetType() && a.Messenger.DeviceKey == messenger.DeviceKey)) + { + Debug.Console(0, this, $"Messenger of type {messenger.GetType().Name} already exists. Skipping actions for {messenger.Key}"); + return; + } + + actionList.Add(new MobileControlAction(messenger, action)); + return; } - else + + actionList = new List { - Debug.Console(1, this, - "Cannot add action with key '{0}' because key already exists in ActionDictionary.", key); - } + new MobileControlAction(messenger, action) + }; + + _actionDictionary.Add(messenger.MessagePath, actionList); } /// @@ -504,28 +993,12 @@ public void RemoveAction(string key) } } - /// - /// - /// - /// - public void AddBridge(MobileControlBridgeBase bridge) + public MobileControlBridgeBase GetRoomBridge(string key) { - _roomBridges.Add(bridge); - var b = bridge as IDelayedConfiguration; - if (b != null) - { - Debug.Console(0, this, "Adding room bridge with delayed configuration"); - b.ConfigurationIsReady += bridge_ConfigurationIsReady; - } - else - { - Debug.Console(0, this, "Adding room bridge and sending configuration"); - - RegisterSystemToServer(); - } + return _roomBridges.FirstOrDefault((r) => r.RoomKey.Equals(key)); } - public MobileControlBridgeBase GetRoomBridge(string key) + public IMobileControlRoomMessenger GetRoomMessenger(string key) { return _roomBridges.FirstOrDefault((r) => r.RoomKey.Equals(key)); } @@ -535,7 +1008,7 @@ public MobileControlBridgeBase GetRoomBridge(string key) /// /// /// - private void bridge_ConfigurationIsReady(object sender, EventArgs e) + private void Bridge_ConfigurationIsReady(object sender, EventArgs e) { Debug.Console(1, this, "Bridge ready. Registering"); @@ -553,7 +1026,7 @@ private void bridge_ConfigurationIsReady(object sender, EventArgs e) { SendInitialMessage(); } - + } /// @@ -563,7 +1036,6 @@ private void bridge_ConfigurationIsReady(object sender, EventArgs e) private void ReconnectToServerTimerCallback(object o) { Debug.Console(1, this, "Attempting to reconnect to server..."); - //RegisterSystemToServer(); ConnectWebsocketClient(); } @@ -587,190 +1059,27 @@ private void AuthorizeSystem(string code) if (string.IsNullOrEmpty(Config.ServerUrl)) { CrestronConsole.ConsoleCommandResponse( - "Mobile control API address is not set. Check portal configuration"); + "Mobile control API address is not set. Check portal configuration"); return; } + var authTask = ApiService.SendAuthorizationRequest(Host, code, SystemUuid); - try + authTask.ContinueWith(t => { - string path = string.Format("/api/system/grantcode/{0}/{1}", code, SystemUuid); - string url = string.Format("{0}{1}", Host, path); - Debug.Console(0, this, "Authorizing to: {0}", url); + var response = t.Result; - if (Host.StartsWith("https:")) - { - DispatchHttpsAuthorizationRequest(url); - } - else + if (response.Authorized) { - var req = new HttpClientRequest(); - req.Url.Parse(url); - - var c = new HttpClient {AllowAutoRedirect = false}; - c.DispatchAsync(req, (r, e) => - { - CheckHttpDebug(r, e); - if (e == HTTP_CALLBACK_ERROR.COMPLETED) - { - switch (r.Code) - { - case 200: - Debug.Console(0, "System authorized, sending config."); - RegisterSystemToServer(); - break; - case 404: - if (r.ContentString.Contains("codeNotFound")) - { - Debug.Console(0, "Authorization failed, code not found for system UUID {0}", - SystemUuid); - } - else if (r.ContentString.Contains("uuidNotFound")) - { - Debug.Console(0, - "Authorization failed, uuid {0} not found. Check Essentials configuration is correct", - SystemUuid); - } - break; - case 301: - { - var newUrl = r.Header.GetHeaderValue("Location"); - var newHostValue = newUrl.Substring(0, - newUrl.IndexOf(path, StringComparison.Ordinal)); - Debug.Console(0, this, - "ERROR: Mobile control API has moved. Please adjust configuration to \"{0}\"", - newHostValue); - } - break; - default: - Debug.Console(0, "http authorization failed, code {0}: {1}", r.Code, r.ContentString); - break; - } - } - else - { - if (r != null) - { - Debug.Console(0, this, "Error in http authorization (A) {0}: {1}", r.Code, e); - } - else - { - Debug.Console(0, this, "Error in http authorization (B) {0}", e); - } - } - }); + Debug.Console(0, this, "System authorized, sending config."); + RegisterSystemToServer(); + return; } - } - catch (Exception e) - { - Debug.Console(0, this, "Error in authorizing (C): {0}", e.Message); - } - } - - /// - /// Dispatchs and handles an Https Authorization Request - /// - /// Url to dispatch request to - private void DispatchHttpsAuthorizationRequest(string url) - { - var req = new HttpsClientRequest(); - req.Url.Parse(url); - - var JsonHeader = new HttpsHeader("content-type", "application/json"); - - req.ContentString = "SOME STUFF HERE"; - var c = new HttpsClient {HostVerification = false, PeerVerification = false, Verbose = true}; - - c.DispatchAsync(req, (r, e) => - { - if (e == HTTPS_CALLBACK_ERROR.COMPLETED) - { - ProcessAuthorizationResponse(r); - } - else - { - if (r != null) - { - Debug.Console(0, this, "Error in http authorization (A) {0}: {1}", r.Code, e); - } - else - { - Debug.Console(0, this, "Error in http authorization (B) {0}", e); - } - } + Debug.Console(0, this, response.Reason); }); } - private void MyCallBackResponseHandler(HttpsClientResponse r, HTTPS_CALLBACK_ERROR e) - { - if (r.Code != 200) - { - Debug.Console(2, this, "Print Error {0}", e); - } - else - { - Debug.Console(2, this, "Got valid response {0}", r.Code); - } - - } - - /// - /// Processes HttpsClientResponse and registers system to server as necessary - /// - /// Response from authorization request - private void ProcessAuthorizationResponse(HttpsClientResponse r) - { - if (r.Code == 200) - { - Debug.Console(0, "System authorized, sending config."); - RegisterSystemToServer(); - } - else if (r.Code == 404 && String.IsNullOrEmpty(r.ContentString)) - { - Debug.Console(0, "https authorization failed, code {0}", r.Code); - if (String.IsNullOrEmpty(r.ContentString)) - { - Debug.Console(0, "content: {0}", r.ContentString); - } - - if (r.ContentString.Contains("codeNotFound")) - { - Debug.Console(0, "code not found for system UUID {0}", - SystemUuid); - } - else if (r.ContentString.Contains("uuidNotFound")) - { - Debug.Console(0, - "uuid {0} not found. Check Essentials configuration is correct", - SystemUuid); - } - } - else if (r.Code == 301 && r.Header != null) - { - Debug.Console(0, "https authorization failed, code {0}", r.Code); - if (String.IsNullOrEmpty(r.ContentString)) - { - Debug.Console(0, "content {0}", r.ContentString); - } - - var newUrl = r.Header.GetHeaderValue("Location"); - var newHostValue = newUrl.Substring(0, - newUrl.IndexOf(r.ResponseUrl, StringComparison.Ordinal)); - Debug.Console(0, this, - "ERROR: Mobile control API has moved. Please adjust configuration to \"{0}\"", - newHostValue); - } - else - { - Debug.Console(0, "https authorization failed, code {0}", r.Code); - if (String.IsNullOrEmpty(r.ContentString)) - { - Debug.Console(0, "Content {0}", r.ContentString); - } - } - } - /// /// Dumps info in response to console command. /// @@ -853,6 +1162,7 @@ Not Enabled in Config. @" Client {0}: Room Key: {1} +Touchpanel Key: {6} Token: {2} Client URL: {3} Connected: {4} @@ -863,7 +1173,7 @@ Not Enabled in Config. clientContext.Key, string.Format("{0}{1}", _directServer.UserAppUrlPrefix, clientContext.Key), isAlive, -duration); +duration, clientContext.Value.Token.TouchpanelKey); clientNo++; } } @@ -880,7 +1190,7 @@ Not Enabled in Config. /// /// Registers the room with the server /// - private void RegisterSystemToServer() + public void RegisterSystemToServer() { #if SERIES4 if (!Config.EnableApiServer) @@ -913,15 +1223,13 @@ private void ConnectWebsocketClient() // set to 99999 to let things work on 4-Series if ((CrestronEnvironment.ProgramCompatibility & eCrestronSeries.Series4) == eCrestronSeries.Series4) { - _wsClient2.Log.Level = (LogLevel) 99999; + _wsClient2.Log.Level = (LogLevel)99999; } else if ((CrestronEnvironment.ProgramCompatibility & eCrestronSeries.Series3) == eCrestronSeries.Series3) { _wsClient2.Log.Level = _wsLogLevel; } - //_wsClient2.Log.Level = _wsLogLevel; - //This version of the websocket client is TLS1.2 ONLY //Fires OnMessage event when PING is received. @@ -1007,9 +1315,9 @@ private void HandleOpen(object sender, EventArgs e) StopServerReconnectTimer(); StartPingTimer(); Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Mobile Control API connected"); - SendMessageObject(new + SendMessageObject(new MobileControlMessage { - type = "hello" + Type = "hello" }); } @@ -1073,14 +1381,23 @@ private void SendInitialMessage() { Debug.Console(1, this, "Sending initial join message"); + var touchPanels = DeviceManager.AllDevices.OfType().Where(tp => !tp.UseDirectServer).Select((tp) => + { + return new + { + touchPanelKey = tp.Key, + roomKey = tp.DefaultRoomKey + }; + }); - var msg = new + var msg = new MobileControlMessage { - type = "join", - content = new + Type = "join", + Content = JToken.FromObject(new { config = GetConfigWithPluginVersion(), - } + touchPanels + }) }; SendMessageObject(msg); @@ -1122,7 +1439,7 @@ public MobileControlEssentialsConfig GetConfigWithPluginVersion() /// Sends any object type to server /// /// - public void SendMessageObject(object o) + public void SendMessageObject(IMobileControlMessage o) { #if SERIES4 if (Config.EnableApiServer) @@ -1142,7 +1459,7 @@ public void SendMessageObject(object o) #if SERIES4 public void SendMessageObjectToDirectClient(object o) { - if(Config.DirectServer != null && Config.DirectServer.EnableDirectServer && _directServer != null) + if (Config.DirectServer != null && Config.DirectServer.EnableDirectServer && _directServer != null) { _transmitToClientsQueue.Enqueue(new MessageToClients(o, _directServer)); } @@ -1203,8 +1520,6 @@ private void PingTimerCallback(object o) HandleConnectFailure(); } - - } /// @@ -1236,9 +1551,9 @@ private void StopServerReconnectTimer() /// private void HandleHeartBeat(JToken content) { - SendMessageObject(new + SendMessageObject(new MobileControlMessage { - type = "/system/heartbeatAck" + Type = "/system/heartbeatAck" }); var code = content["userCode"]; @@ -1259,12 +1574,12 @@ private void HandleClientJoined(JToken content) var roomKey = content["roomKey"].Value(); - SendMessageObject(new MobileControlResponseMessage() - { - Type = "/system/roomKey", - ClientId = clientId, - Content = roomKey - }); + SendMessageObject(new MobileControlMessage + { + Type = "/system/roomKey", + ClientId = clientId, + Content = roomKey + }); } private void HandleUserCode(JToken content) @@ -1284,10 +1599,10 @@ private void HandleUserCode(JToken content, Action action) } catch { - qrChecksum = new JValue(String.Empty); + qrChecksum = new JValue(string.Empty); } - Debug.Console(1, this, "QR checksum: {0}", qrChecksum == null ? String.Empty : qrChecksum.Value()); + Debug.Console(1, this, "QR checksum: {0}", qrChecksum == null ? string.Empty : qrChecksum.Value()); if (code == null) { @@ -1307,40 +1622,6 @@ private void HandleUserCode(JToken content, Action action) action(code.Value(), qrChecksum.Value()); } - /// - /// Outputs debug info when enabled - /// - /// - /// - private void CheckHttpDebug(HttpClientResponse r, HTTP_CALLBACK_ERROR e) - { - if (!_httpDebugEnabled) - { - return; - } - - try - { - Debug.Console(0, this, "------ Begin HTTP Debug ---------------------------------------"); - if (r != null) - { - Debug.Console(0, this, "HTTP Response URL: {0}", r.ResponseUrl ?? "NONE"); - Debug.Console(0, this, "HTTP Response code: {0}", r.Code); - Debug.Console(0, this, "HTTP Response content: \r{0}", r.ContentString); - } - else - { - Debug.Console(0, this, "No HTTP response"); - } - Debug.Console(0, this, "HTTP Response 'error' {0}", e); - Debug.Console(0, this, "------ End HTTP Debug -----------------------------------------"); - } - catch (Exception ex) - { - Debug.Console(0, this, "HttpDebugError: {0}", ex); - } - } - public void HandleClientMessage(string message) { _receiveQueue.Enqueue(new ProcessStringMessage(message, ParseStreamRx)); @@ -1349,194 +1630,65 @@ public void HandleClientMessage(string message) /// /// /// - private void ParseStreamRx(string message) + private void ParseStreamRx(string messageText) { - if (string.IsNullOrEmpty(message)) + if (string.IsNullOrEmpty(messageText)) { return; } - if (!message.Contains("/system/heartbeat")) + if (!messageText.Contains("/system/heartbeat")) { - Debug.Console(2, this, "Message RX: {0}", message); + Debug.LogMessage(LogEventLevel.Debug, "Message RX: {messageText}", this, messageText); } try { - var messageObj = JObject.Parse(message); - - var type = messageObj["type"].Value(); + var message = JsonConvert.DeserializeObject(messageText); - switch (type) + switch (message.Type) { case "hello": SendInitialMessage(); break; case "/system/heartbeat": - HandleHeartBeat(messageObj["content"]); + HandleHeartBeat(message.Content); break; case "/system/userCode": - HandleUserCode(messageObj["content"]); + HandleUserCode(message.Content); break; case "/system/clientJoined": - HandleClientJoined(messageObj["content"]); + HandleClientJoined(message.Content); break; case "raw": - { - var wrapper = messageObj["content"].ToObject(); + var wrapper = message.Content.ToObject(); DeviceJsonApi.DoDeviceAction(wrapper); - } break; case "close": Debug.Console(1, this, "Received close message from server."); break; default: - if (_actionDictionary.ContainsKey(type)) - { - var action = _actionDictionary[type]; - - if (action is Action) - { - (action as Action)(); - } - else if (action is PressAndHoldAction) - { - var stateString = messageObj["content"]["state"].Value(); - - // Look for a button press event - if (!string.IsNullOrEmpty(stateString)) - { - switch (stateString) - { - case "true": - { - if (!_pushedActions.ContainsKey(type)) - { - _pushedActions.Add(type, new CTimer(o => - { - var pressAndHoldAction = action as PressAndHoldAction; - if (pressAndHoldAction != null) - { - pressAndHoldAction(false); - } - _pushedActions.Remove(type); - }, null, ButtonHeartbeatInterval)); - } - // Maybe add an else to reset the timer - break; - } - case "held": - { - if (_pushedActions.ContainsKey(type)) - { - _pushedActions[type].Reset(ButtonHeartbeatInterval); - } - return; - } - case "false": - { - if (_pushedActions.ContainsKey(type)) - { - _pushedActions[type].Stop(); - _pushedActions.Remove(type); - } - break; - } - } - - (action as PressAndHoldAction)(stateString == "true"); - } - } - else if (action is Action) - { - var stateString = messageObj["content"]["state"].Value(); + var handlersKv = _actionDictionary.FirstOrDefault(kv => message.Type.StartsWith(kv.Key)); - if (!string.IsNullOrEmpty(stateString)) - { - (action as Action)(stateString.ToLower() == "true"); - } - } - else if (action is Action) - { - (action as Action)(messageObj["content"]["value"].Value()); - } - else if (action is Action) - { - (action as Action)(messageObj["content"]["value"].Value()); - } - else if (action is Action) - { - (action as Action)(messageObj["content"]["value"].Value()); - } - else if (action is Action) - { - (action as Action)(messageObj["content"] - .ToObject()); - } - else if (action is ClientSpecificUpdateRequest) - { - var clientId = messageObj["clientId"].ToString(); - - - (action as ClientSpecificUpdateRequest).ResponseMethod(clientId); + if (handlersKv.Key == null) + { + Debug.Console(1, this, "-- Warning: Incoming message has no registered handler"); + break; + } - //if (respObj != null) - //{ - // respObj.ClientId = clientId; + var handlers = handlersKv.Value; - // SendMessageObject(respObj); - //} - } - else if (action is Action) - { - (action as Action)( - messageObj["content"].ToObject()); - } - else if (action is Action>) - { - (action as Action>)( - messageObj["content"].ToObject>()); - } - else if (action is Action>) - { - (action as Action>)( - messageObj["content"].ToObject>()); - } - else if (action is Action) - { - (action as Action)(messageObj["content"].ToObject()); - } - else if (action is Action) - { - (action as Action)(messageObj["content"].ToObject()); - } - else if (action is Action) - { - (action as Action)(messageObj["content"].ToObject()); - } - else if (action is Action) - { - (action as Action)(messageObj["content"].ToObject()); - } - else if (action is Action) - { - (action as Action)(messageObj["content"].ToObject()); - } - else if (action is UserCodeChanged) - { - this.HandleUserCode(messageObj["content"], (action as UserCodeChanged).UpdateUserCode); - } - } - else + foreach (var handler in handlers) { - Debug.Console(1, this, "-- Warning: Incoming message has no registered handler"); + Task.Run(() => handler.Action(message.Type, message.ClientId, message.Content)); } + break; } } catch (Exception err) { - Debug.Console(1, this, "Unable to parse message: {0}", err); + Debug.LogMessage(err, "Unable to parse {message}:{exception}", this, messageText, err); } } @@ -1568,16 +1720,16 @@ private void TestHttpRequest(string s) switch (tokens[0].ToLower()) { case "get": - { - var resp = new HttpClient().Get(url); - CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp); - } + { + var resp = new HttpClient().Get(url); + CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp); + } break; case "post": - { - var resp = new HttpClient().Post(url, new byte[] {}); - CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp); - } + { + var resp = new HttpClient().Post(url, new byte[] { }); + CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp); + } break; default: CrestronConsole.ConsoleCommandResponse("Only get or post supported\r"); @@ -1603,7 +1755,7 @@ private void PrintTestHttpRequestUsage() public class ClientSpecificUpdateRequest { - public ClientSpecificUpdateRequest(Action action ) + public ClientSpecificUpdateRequest(Action action) { ResponseMethod = action; } @@ -1620,20 +1772,4 @@ public UserCodeChanged(Action updateMethod) UpdateUserCode = updateMethod; } } - -#if SERIES4 - public class MobileControlResponseMessage: IMobileControlResponseMessage -#else - public class MobileControlResponseMessage -#endif - { - [JsonProperty("type")] - public string Type { get; set; } - - [JsonProperty("clientId")] - public object ClientId { get; set; } - - [JsonProperty("content")] - public object Content { get; set; } - } } \ No newline at end of file diff --git a/3-series/RoomBridges/MobileControlBridgeBase.cs b/3-series/RoomBridges/MobileControlBridgeBase.cs index 64db272..60485f7 100644 --- a/3-series/RoomBridges/MobileControlBridgeBase.cs +++ b/3-series/RoomBridges/MobileControlBridgeBase.cs @@ -1,10 +1,7 @@ -using System; -using PepperDash.Essentials.Core; - -using PepperDash.Core; - -using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Core; using PepperDash.Essentials.AppServer.Messengers; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using System; namespace PepperDash.Essentials @@ -12,7 +9,7 @@ namespace PepperDash.Essentials /// /// /// - public abstract class MobileControlBridgeBase : MessengerBase, IMobileControlRoomBridge + public abstract class MobileControlBridgeBase : MessengerBase, IMobileControlRoomMessenger { public event EventHandler UserCodeChanged; @@ -20,8 +17,11 @@ public abstract class MobileControlBridgeBase : MessengerBase, IMobileControlRoo public event EventHandler ClientJoined; - public MobileControlSystemController Parent { get; private set; } + public event EventHandler AppUrlChanged; + + public IMobileControl Parent { get; private set; } + public string AppUrl { get; private set; } public string UserCode { get; private set; } public string QrCodeUrl { get; protected set; } @@ -39,7 +39,7 @@ protected MobileControlBridgeBase(string key, string messagePath) { } - protected MobileControlBridgeBase(string key, string messagePath, Device device) + protected MobileControlBridgeBase(string key, string messagePath, IKeyName device) : base(key, messagePath, device) { } @@ -49,11 +49,11 @@ protected MobileControlBridgeBase(string key, string messagePath, Device device) /// as adding actions to parent /// /// - public virtual void AddParent(MobileControlSystemController parent) + public virtual void AddParent(IMobileControl parent) { Parent = parent; - McServerUrl = Parent.Config.ClientAppUrl; + McServerUrl = Parent.ClientAppUrl; RegisterWithAppServer(parent); } @@ -87,6 +87,17 @@ public void SetUserCode(string code, string qrChecksum) SetUserCode(code); } + public virtual void UpdateAppUrl(string url) + { + AppUrl = url; + + var handler = AppUrlChanged; + + if (handler == null) return; + + handler(this, new EventArgs()); + } + /// /// Empty method in base class. Override this to add functionality /// when code changes @@ -95,7 +106,7 @@ protected virtual void UserCodeChange() { Debug.Console(1, this, "Server user code changed: {0}", UserCode); - var qrUrl = string.Format("{0}/api/rooms/{1}/{3}/qr?x={2}", Parent.Host, Parent.SystemUuid, new Random().Next()); + var qrUrl = string.Format($"{Parent.Host}/api/rooms/{Parent.SystemUuid}/{RoomKey}/qr?x={new Random().Next()}"); QrCodeUrl = qrUrl; Debug.Console(1, this, "Server user code changed: {0} - {1}", UserCode, qrUrl); @@ -105,29 +116,17 @@ protected virtual void UserCodeChange() protected void OnUserCodeChanged() { - var handler = UserCodeChanged; - if (handler != null) - { - handler(this, new EventArgs()); - } + UserCodeChanged?.Invoke(this, new EventArgs()); } protected void OnUserPromptedForCode() { - var handler = UserPromptedForCode; - if (handler != null) - { - handler(this, new EventArgs()); - } + UserPromptedForCode?.Invoke(this, new EventArgs()); } protected void OnClientJoined() { - var handler = ClientJoined; - if (handler != null) - { - handler(this, new EventArgs()); - } + ClientJoined?.Invoke(this, new EventArgs()); } } } \ No newline at end of file diff --git a/3-series/RoomBridges/MobileControlEssentialsRoomBridge.cs b/3-series/RoomBridges/MobileControlEssentialsRoomBridge.cs index 0add835..4fe7786 100644 --- a/3-series/RoomBridges/MobileControlEssentialsRoomBridge.cs +++ b/3-series/RoomBridges/MobileControlEssentialsRoomBridge.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Crestron.SimplSharp.Ssh; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.AppServer.Messengers; @@ -13,12 +12,20 @@ using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Devices.Common.AudioCodec; using PepperDash.Essentials.Devices.Common.Cameras; -using PepperDash.Essentials.Devices.Common.SoftCodec; -using PepperDash.Essentials.Core.Lighting; -using PepperDash.Essentials.Core.Shades; using Newtonsoft.Json; using Newtonsoft.Json.Converters; +using PepperDash.Essentials.Devices.Common.Room; +using IShades = PepperDash.Essentials.Core.Shades.IShades; +using ShadeBase = PepperDash.Essentials.Devices.Common.Shades.ShadeBase; +using PepperDash.Essentials.Devices.Common.TouchPanel; +using Crestron.SimplSharp; +using Volume = PepperDash.Essentials.Room.MobileControl.Volume; +using PepperDash.Essentials.Core.CrestronIO; +using PepperDash.Essentials.Core.Lighting; +using PepperDash.Essentials.Core.Shades; + + #if SERIES4 using PepperDash.Essentials.AppServer; #endif @@ -27,11 +34,10 @@ namespace PepperDash.Essentials { public class MobileControlEssentialsRoomBridge : MobileControlBridgeBase { + private List _touchPanelTokens = new List(); public IEssentialsRoom Room { get; private set; } - public string DefaultRoomKey - { - get; private set; } + public string DefaultRoomKey { get; private set; } /// /// /// @@ -45,23 +51,13 @@ public override string RoomKey get { return Room.Key; } } - /// - /// - /// - /// - public MobileControlEssentialsRoomBridge(EssentialsRoomBase room) : - this(string.Format("mobileControlBridge-{0}", room.Key), room.Key, room) - { - Room = room; - } - public MobileControlEssentialsRoomBridge(IEssentialsRoom room) : - this(string.Format("mobileControlBridge-{0}", room.Key), room.Key, room as Device) + this($"mobileControlBridge-{room.Key}", room.Key, room) { Room = room; } - public MobileControlEssentialsRoomBridge(string key, string roomKey, Device room) : base(key, string.Format(@"/room/{0}/status", roomKey), room) + public MobileControlEssentialsRoomBridge(string key, string roomKey, IEssentialsRoom room) : base(key, $"/room/{room.Key}", room as Device) { DefaultRoomKey = roomKey; @@ -69,7 +65,7 @@ public MobileControlEssentialsRoomBridge(string key, string roomKey, Device room } #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif @@ -81,158 +77,202 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle Debug.Console(0, this, "Registering Actions with AppServer"); - appServerController.AddAction(string.Format(@"/room/{0}/promptForCode", Room.Key), new Action(OnUserPromptedForCode)); - appServerController.AddAction(string.Format(@"/room/{0}/clientJoined", Room.Key), new Action(OnClientJoined)); + AddAction("/promptForCode", (id, content) => OnUserPromptedForCode()); + AddAction("/clientJoined", (id, content) => OnClientJoined()); - appServerController.AddAction(string.Format(@"/room/{0}/userCode", Room.Key), - new UserCodeChanged(SetUserCode)); + AddAction("/touchPanels", (id, content) => OnTouchPanelsUpdated(content)); - // Source Changes and room off - appServerController.AddAction(string.Format(@"/room/{0}/status", Room.Key), new ClientSpecificUpdateRequest((id) => SendFullStatusForClientId(id, Room))); + AddAction($"/userApp", (id, content) => OnUserAppUpdated(content)); - var routeRoom = Room as IRunRouteAction; - if (routeRoom != null) - appServerController.AddAction(string.Format(@"/room/{0}/source", Room.Key), - new Action(c => - { - var sourceListKey = string.Empty; + AddAction("/userCode", (id, content) => + { + var msg = content.ToObject(); - routeRoom.RunRouteAction(c.SourceListItem, sourceListKey); + SetUserCode(msg.UserCode, msg.QrChecksum ?? string.Empty); + }); - })); - var directRouteRoom = Room as IRunDirectRouteAction; - if (directRouteRoom != null) + // Source Changes and room off + AddAction("/status", (id, content) => { - appServerController.AddAction(String.Format("/room/{0}/directRoute", Room.Key), new Action((d) => directRouteRoom.RunDirectRoute(d.SourceKey, d.DestinationKey))); - } + SendFullStatusForClientId(id, Room); + }); + + if (Room is IRunRouteAction routeRoom) + AddAction("/source", (id, content) => + { + var msg = content.ToObject(); - var defaultRoom = Room as IRunDefaultPresentRoute; - if (defaultRoom != null) - appServerController.AddAction(string.Format(@"/room/{0}/defaultsource", Room.Key), - new Action(() => defaultRoom.RunDefaultPresentRoute())); + Debug.Console(2, this, "Received request to route to source: {0} on list: {1}", msg.SourceListItemKey, msg.SourceListKey); - var volumeRoom = Room as IHasCurrentVolumeControls; - if (volumeRoom != null) + routeRoom.RunRouteAction(msg.SourceListItemKey, msg.SourceListKey); + }); + + if (Room is IRunDirectRouteAction directRouteRoom) { - appServerController.AddAction(string.Format(@"/room/{0}/volumes/master/level", Room.Key), new Action(u => + AddAction("/directRoute", (id, content) => { - var basicVolumeWithFeedback = volumeRoom.CurrentVolumeControls as IBasicVolumeWithFeedback; - if (basicVolumeWithFeedback != null) - basicVolumeWithFeedback.SetVolume(u); - })); - appServerController.AddAction(string.Format(@"/room/{0}/volumes/master/muteToggle", Room.Key), new Action(() => - volumeRoom.CurrentVolumeControls.MuteToggle())); - volumeRoom.CurrentVolumeDeviceChange += Room_CurrentVolumeDeviceChange; + var msg = content.ToObject(); - // Registers for initial volume events, if possible - var currentVolumeDevice = volumeRoom.CurrentVolumeControls as IBasicVolumeWithFeedback; - if (currentVolumeDevice != null) - { - currentVolumeDevice.MuteFeedback.OutputChange += MuteFeedback_OutputChange; - currentVolumeDevice.VolumeLevelFeedback.OutputChange += VolumeLevelFeedback_OutputChange; - } + + Debug.Console(2, this, $"Running direct route from {msg.SourceKey} to {msg.DestinationKey} with signal type {msg.SignalType}"); + + directRouteRoom.RunDirectRoute(msg.SourceKey, msg.DestinationKey, msg.SignalType); + }); } - var sscRoom = Room as IHasCurrentSourceInfoChange; - if (sscRoom != null) - sscRoom.CurrentSourceChange += Room_CurrentSingleSourceChange; - var vcRoom = Room as IHasVideoCodec; - if (vcRoom != null && vcRoom.VideoCodec != null) + if (Room is IRunDefaultPresentRoute defaultRoom) + AddAction("/defaultsource", (id, content) => defaultRoom.RunDefaultPresentRoute()); + + if (Room is IHasCurrentVolumeControls volumeRoom) { - var key = vcRoom.VideoCodec.Key + "-" + appServerController.Key; + AddAction("/volumes/master/level", (id, content) => + { + var msg = content.ToObject>(); + + + if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) + basicVolumeWithFeedback.SetVolume(msg.Value); + }); + + AddAction("/volumes/master/muteToggle", (id, content) => volumeRoom.CurrentVolumeControls.MuteToggle()); - if (!appServerController.CheckForDeviceMessenger(key)) + AddAction("/volumes/master/muteOn", (id, content) => { - var zr = vcRoom.VideoCodec as PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom.ZoomRoom; - if (zr != null) + if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) + basicVolumeWithFeedback.MuteOn(); + }); + + AddAction("/volumes/master/muteOff", (id, content) => + { + if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) + basicVolumeWithFeedback.MuteOff(); + }); + + AddAction("/volumes/master/volumeUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => { - var zrMessenger = new ZoomRoomMessenger(key, zr, String.Format("/device/{0}", vcRoom.VideoCodec.Key)); - appServerController.AddDeviceMessenger(zrMessenger); + if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) + { + basicVolumeWithFeedback.VolumeUp(b); + } } - else + )); + + AddAction("/volumes/master/volumeDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => + { + if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) { - var vcMessenger = new VideoCodecBaseMessenger(key, vcRoom.VideoCodec, String.Format("/device/{0}", vcRoom.VideoCodec.Key)); - appServerController.AddDeviceMessenger(vcMessenger); + basicVolumeWithFeedback.VolumeDown(b); } } + )); - vcRoom.IsSharingFeedback.OutputChange += IsSharingFeedback_OutputChange; - } - - var acRoom = Room as IHasAudioCodec; - if (acRoom != null && acRoom.AudioCodec != null) - { - var key = acRoom.AudioCodec.Key + "-" + appServerController.Key; + volumeRoom.CurrentVolumeDeviceChange += Room_CurrentVolumeDeviceChange; - if (!appServerController.CheckForDeviceMessenger(key)) + // Registers for initial volume events, if possible + if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback currentVolumeDevice) { - var acMessenger = new AudioCodecBaseMessenger(key, acRoom.AudioCodec, - String.Format("/device/{0}", acRoom.AudioCodec.Key)); - appServerController.AddDeviceMessenger(acMessenger); + Debug.Console(2, this, "Registering for volume feedback events"); + + currentVolumeDevice.MuteFeedback.OutputChange += MuteFeedback_OutputChange; + currentVolumeDevice.VolumeLevelFeedback.OutputChange += VolumeLevelFeedback_OutputChange; } } - var vtcRoom = Room as IEssentialsHuddleVtc1Room; - if (vtcRoom != null) + if (Room is IHasCurrentSourceInfoChange sscRoom) + sscRoom.CurrentSourceChange += Room_CurrentSingleSourceChange; + + if (Room is IEssentialsHuddleVtc1Room vtcRoom) { if (vtcRoom.ScheduleSource != null) { - var key = vtcRoom.Key + "-" + appServerController.Key; + var key = vtcRoom.Key + "-" + Key; - if (!appServerController.CheckForDeviceMessenger(key)) + if (!AppServerController.CheckForDeviceMessenger(key)) { var scheduleMessenger = new IHasScheduleAwarenessMessenger(key, vtcRoom.ScheduleSource, - string.Format("/room/{0}/schedule", vtcRoom.Key)); - appServerController.AddDeviceMessenger(scheduleMessenger); + $"/room/{vtcRoom.Key}"); + AppServerController.AddDeviceMessenger(scheduleMessenger); } } vtcRoom.InCallFeedback.OutputChange += InCallFeedback_OutputChange; } - var privacyRoom = Room as IPrivacy; - if (privacyRoom != null) + if (Room is IPrivacy privacyRoom) { - appServerController.AddAction(string.Format(@"/room/{0}/volumes/master/privacyMuteToggle", Room.Key), new Action(privacyRoom.PrivacyModeToggle)); + AddAction("/volumes/master/privacyMuteToggle", (id, content) => privacyRoom.PrivacyModeToggle()); privacyRoom.PrivacyModeIsOnFeedback.OutputChange += PrivacyModeIsOnFeedback_OutputChange; } - SetupDeviceMessengers(); + //SetupDeviceMessengers(); - var defCallRm = Room as IRunDefaultCallRoute; - if (defCallRm != null) + if (Room is IRunDefaultCallRoute defCallRm) { - appServerController.AddAction(string.Format(@"/room/{0}/activityVideo", Room.Key), - new Action(() => defCallRm.RunDefaultCallRoute())); + AddAction("/activityVideo", (id, content) => defCallRm.RunDefaultCallRoute()); } - appServerController.AddAction(string.Format(@"/room/{0}/shutdownStart", Room.Key), - new Action(() => Room.StartShutdown(eShutdownType.Manual))); - appServerController.AddAction(string.Format(@"/room/{0}/shutdownEnd", Room.Key), - new Action(() => Room.ShutdownPromptTimer.Finish())); - appServerController.AddAction(string.Format(@"/room/{0}/shutdownCancel", Room.Key), - new Action(() => Room.ShutdownPromptTimer.Cancel())); + //AddAction("/shutdownStart", (id, content) => Room.StartShutdown(eShutdownType.Manual)); + + //AddAction("/shutdownEnd", (id, content) => Room.ShutdownPromptTimer.Finish()); + + //AddAction("/shutdownCancel", (id, content) => Room.ShutdownPromptTimer.Cancel()); Room.OnFeedback.OutputChange += OnFeedback_OutputChange; Room.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange; Room.IsWarmingUpFeedback.OutputChange += IsWarmingUpFeedback_OutputChange; - Room.ShutdownPromptTimer.HasStarted += ShutdownPromptTimer_HasStarted; - Room.ShutdownPromptTimer.HasFinished += ShutdownPromptTimer_HasFinished; - Room.ShutdownPromptTimer.WasCancelled += ShutdownPromptTimer_WasCancelled; + //Room.ShutdownPromptTimer.HasStarted += ShutdownPromptTimer_HasStarted; + //Room.ShutdownPromptTimer.HasFinished += ShutdownPromptTimer_HasFinished; + //Room.ShutdownPromptTimer.WasCancelled += ShutdownPromptTimer_WasCancelled; AddTechRoomActions(); } - private void InCallFeedback_OutputChange(object sender, FeedbackEventArgs e) + private void OnTouchPanelsUpdated(JToken content) { - var state = new RoomStateMessage(); + var message = content.ToObject(); + + _touchPanelTokens = message.TouchPanels; + + UpdateTouchPanelAppUrls(message.UserAppUrl); + } + + private void UpdateTouchPanelAppUrls(string userAppUrl) + { + foreach (var tp in _touchPanelTokens) + { + var dev = DeviceManager.AllDevices.OfType().FirstOrDefault((tpc) => tpc.Key.Equals(tp.TouchpanelKey, StringComparison.InvariantCultureIgnoreCase)); + + if (dev == null) + { + continue; + } + + //UpdateAppUrl($"{userAppUrl}?token={tp.Token}"); + + dev.SetAppUrl($"{userAppUrl}?token={tp.Token}"); + } + } + + private void OnUserAppUpdated(JToken content) + { + var message = content.ToObject(); + + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Updating User App URL to {userAppUrl}. Full Message: {@message}", this, message.UserAppUrl, content); - state.IsInCall = e.BoolValue; + UpdateTouchPanelAppUrls(message.UserAppUrl); + } + + private void InCallFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + var state = new RoomStateMessage + { + IsInCall = e.BoolValue + }; PostStatusMessage(state); } @@ -244,9 +284,8 @@ private void GetRoom() return; } - var tempRoom = DeviceManager.GetDeviceForKey(DefaultRoomKey) as IEssentialsRoom; - if (tempRoom == null) + if (!(DeviceManager.GetDeviceForKey(DefaultRoomKey) is IEssentialsRoom tempRoom)) { Debug.Console(0, this, "Room with key {0} not found or is not an Essentials Room", DefaultRoomKey); return; @@ -267,212 +306,43 @@ protected override void UserCodeChange() OnUserCodeChanged(); } - /// - /// Override of base: calls base to add parent and then registers actions and events. - /// - /// - public override void AddParent(MobileControlSystemController parent) - { - base.AddParent(parent); + /* /// + /// Override of base: calls base to add parent and then registers actions and events. + /// + /// + public override void AddParent(MobileControlSystemController parent) + { + base.AddParent(parent); - } + }*/ private void AddTechRoomActions() { - var techRoom = Room as EssentialsTechRoom; - - if (techRoom == null) + if (!(Room is IEssentialsTechRoom techRoom)) { return; } - SetTunerActions(techRoom); - - CreateScheduleMessenger(techRoom); - - Parent.AddAction(String.Format("/room/{0}/roomPowerOn",techRoom.Key), new Action(techRoom.RoomPowerOn)); - Parent.AddAction(String.Format("/room/{0}/roomPowerOff", techRoom.Key), new Action(techRoom.RoomPowerOff)); + AddAction("/roomPowerOn", (id, content) => techRoom.RoomPowerOn()); + AddAction("/roomPowerOff", (id, content) => techRoom.RoomPowerOff()); } - private void CreateScheduleMessenger(EssentialsTechRoom techRoom) - { - var scheduleMessenger = new RoomEventScheduleMessenger(techRoom.Key + "-schedule", - String.Format("/room/{0}/schedule", techRoom.Key), techRoom); - Parent.AddDeviceMessenger(scheduleMessenger); - } - - private void SetTunerActions(EssentialsTechRoom techRoom) - { - foreach (var tuner in techRoom.Tuners.Select(t => t.Value).Cast()) - { - var stb = tuner; - stb.LinkActions(Parent); - } - - foreach (var tuner in techRoom.Tuners.Select(t => t.Value).Cast()) - { - var stb = tuner; - stb.LinkActions(Parent); - } - - foreach (var tuner in techRoom.Tuners.Select(t => t.Value).Cast()) - { - var stb = tuner; - stb.LinkActions(Parent); - } - - foreach (var tuner in techRoom.Tuners.Select(t => t.Value).Cast()) - { - var stb = tuner; - stb.LinkActions(Parent); - } - - foreach (var tuner in techRoom.Tuners.Select(t => t.Value).Cast()) - { - var stb = tuner; - stb.LinkActions(Parent); - } - - foreach (var tuner in techRoom.Tuners.Select(t => t.Value).Cast()) - { - var stb = tuner; - stb.LinkActions(Parent); - } - - foreach (var tuner in techRoom.Tuners.Select(t => t.Value).Cast()) - { - var stb = tuner; - stb.LinkActions(Parent); - } - } - - void PrivacyModeIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) + private void PrivacyModeIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) { var state = new RoomStateMessage(); - var volumes = new Volumes(); - - volumes.Master = new Volume("master"); - volumes.Master.PrivacyMuted = e.BoolValue; - - state.Volumes = volumes; - - PostStatusMessage(state); - } - - /// - /// Set up the messengers for each device type - /// - private void SetupDeviceMessengers() - { - foreach (var device in DeviceManager.AllDevices) + var volumes = new Dictionary { - Debug.Console(2, this, "Attempting to set up device messenger for device: {0}", device.Key); - - if (device is CameraBase) - { - var camDevice = device as CameraBase; - Debug.Console(2, this, "Adding CameraBaseMessenger for device: {0}", device.Key); - var cameraMessenger = new CameraBaseMessenger(device.Key + "-" + Parent.Key, camDevice, - "/device/" + device.Key); - Parent.AddDeviceMessenger(cameraMessenger); - - } - - if (device is BlueJeansPc) - { - var softCodecDevice = device as BlueJeansPc; - Debug.Console(2, this, "Adding IRunRouteActionMessnger for device: {0}", device.Key); - var routeMessenger = new RunRouteActionMessenger(device.Key + "-" + Parent.Key, softCodecDevice, - "/device/" + device.Key); - Parent.AddDeviceMessenger(routeMessenger); - - } - - if (device is ITvPresetsProvider) - { - var presetsDevice = device as ITvPresetsProvider; - if (presetsDevice.TvPresets == null) - { - Debug.Console(0, this, "TvPresets is null for device: '{0}'. Skipping DevicePresetsModelMessenger", device.Key); - } - else + { "master", new Volume("master") { - Debug.Console(2, this, "Adding ITvPresetsProvider for device: {0}", device.Key); - var presetsMessenger = new DevicePresetsModelMessenger(device.Key + "-" + Parent.Key, String.Format("/device/{0}/presets", device.Key), - presetsDevice); - Parent.AddDeviceMessenger(presetsMessenger); - - } - } - - if (device is DisplayBase) - { - var display = device as DisplayBase; - Debug.Console(2, this, "Adding actions for device: {0}", device.Key); - - display.LinkActions(Parent); + PrivacyMuted = e.BoolValue + } } + }; - if (device is TwoWayDisplayBase) - { - var display = device as TwoWayDisplayBase; - Debug.Console(2, this, "Adding TwoWayDisplayBase for device: {0}", device.Key); - var twoWayDisplayMessenger = new TwoWayDisplayBaseMessenger(device.Key + "-" + Parent.Key, - String.Format("/device/{0}", device.Key), display); - Parent.AddDeviceMessenger(twoWayDisplayMessenger); - } - - if (device is ICommunicationMonitor) - { - var monitor = device as ICommunicationMonitor; - Debug.Console(2, this, "Adding CommunicationMonitor for device: {0}", device.Key); - var communicationMonitorMessenger = new CommMonitorMessenger(device.Key + "-" + Parent.Key + "-monitor", - String.Format("/device/{0}/commMonitor", device.Key), monitor); - Parent.AddDeviceMessenger(communicationMonitorMessenger); - - } - - if (device is IBasicVolumeWithFeedback) - { - var deviceKey = device.Key; - var volControlDevice = device as IBasicVolumeWithFeedback; - Debug.Console(2, this, "Adding IBasicVolumeControlWithFeedback for device: {0}", deviceKey); - var messenger = new DeviceVolumeMessenger(deviceKey + "-" + Parent.Key + "-volume", - String.Format("/device/{0}/volume", deviceKey), deviceKey, volControlDevice); - Parent.AddDeviceMessenger(messenger); - } - - if (device is LightingBase) - { - var deviceKey = device.Key; - var lightingDevice = device as LightingBase; - Debug.Console(2, this, "Adding LightingBaseMessenger for device: {0}", deviceKey); - var messenger = new LightingBaseMessenger(deviceKey + "-" + Parent.Key, - lightingDevice, string.Format("/device/{0}", deviceKey)); - Parent.AddDeviceMessenger(messenger); - } - - if (device is ShadeBase) - { - var deviceKey = device.Key; - var shadeDevice = device as ShadeBase; - Debug.Console(2, this, "Adding ShadeBaseMessenger for device: {0}", deviceKey); - var messenger = new ShadeBaseMessenger(deviceKey + "-" + Parent.Key, - shadeDevice, string.Format("/device/{0}", deviceKey)); - Parent.AddDeviceMessenger(messenger); - } - - var genericDevice = device as EssentialsDevice; - - if(genericDevice == null) - { - continue; - } + state.Volumes = volumes; - Debug.Console(2, this, "Adding GenericMessenger for device: {0}", genericDevice.Key); - Parent.AddDeviceMessenger(new GenericMessenger(genericDevice.Key + "-" + Parent.Key + "-generic", genericDevice, string.Format("/device/{0}", genericDevice.Key))); - } + PostStatusMessage(state); } /// @@ -486,10 +356,7 @@ private void IsSharingFeedback_OutputChange(object sender, FeedbackEventArgs e) string shareText; bool isSharing; - var vcRoom = Room as IHasVideoCodec; - var srcInfoRoom = Room as IHasCurrentSourceInfoChange; - - if (srcInfoRoom != null && (vcRoom != null && (vcRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue && srcInfoRoom.CurrentSourceInfo != null))) + if (Room is IHasCurrentSourceInfoChange srcInfoRoom && (Room is IHasVideoCodec vcRoom && (vcRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue && srcInfoRoom.CurrentSourceInfo != null))) { shareText = srcInfoRoom.CurrentSourceInfo.PreferredName; isSharing = true; @@ -500,56 +367,59 @@ private void IsSharingFeedback_OutputChange(object sender, FeedbackEventArgs e) isSharing = false; } - var state = new RoomStateMessage(); - - state.Share = new ShareState(); - state.Share.CurrentShareText = shareText; - state.Share.IsSharing = isSharing; + var state = new RoomStateMessage + { + Share = new ShareState + { + CurrentShareText = shareText, + IsSharing = isSharing + } + }; PostStatusMessage(state); } - /// - /// Handler for cancelled shutdown - /// - /// - /// - private void ShutdownPromptTimer_WasCancelled(object sender, EventArgs e) - { - var roomStatus = new JObject {{"state", "wasCancelled"}}; - var message = new JObject {{"type", String.Format("/room/{0}/shutdown/", Room.Key)}, {"content", roomStatus}}; - Parent.SendMessageObject(message); - } - - /// - /// Handler for when shutdown finishes - /// - /// - /// - private void ShutdownPromptTimer_HasFinished(object sender, EventArgs e) - { - var roomStatus = new JObject {{"state", "hasFinished"}}; - var message = new JObject { { "type", String.Format("/room/{0}/shutdown/", Room.Key) }, { "content", roomStatus } }; - Parent.SendMessageObject(message); - } - - /// - /// Handler for when shutdown starts - /// - /// - /// - private void ShutdownPromptTimer_HasStarted(object sender, EventArgs e) - { - var roomStatus = new JObject - { - {"state", "hasStarted"}, - {"duration", Room.ShutdownPromptTimer.SecondsToCount} - }; - var message = new JObject {{"type", String.Format("/room/{0}/shutdown/", Room.Key)}, {"content", roomStatus}}; - Parent.SendMessageObject(message); - // equivalent JS message: - // Post( { type: '/room/status/', content: { shutdown: 'hasStarted', duration: Room.ShutdownPromptTimer.SecondsToCount }) - } + ///// + ///// Handler for cancelled shutdown + ///// + ///// + ///// + //private void ShutdownPromptTimer_WasCancelled(object sender, EventArgs e) + //{ + // var roomStatus = new {state = "wasCancelled" }; + + // PostStatusMessage(JToken.FromObject(roomStatus)); + //} + + ///// + ///// Handler for when shutdown finishes + ///// + ///// + ///// + //private void ShutdownPromptTimer_HasFinished(object sender, EventArgs e) + //{ + // var roomStatus = new { state= "hasFinished" }; + + // PostStatusMessage(JToken.FromObject(roomStatus)); + //} + + ///// + ///// Handler for when shutdown starts + ///// + ///// + ///// + //private void ShutdownPromptTimer_HasStarted(object sender, EventArgs e) + //{ + // var roomStatus = new + // { + // state = "hasStarted", + // duration = Room.ShutdownPromptTimer.SecondsToCount + // }; + + // PostStatusMessage(JToken.FromObject(roomStatus)); + // // equivalent JS message: + // // Post( { type: '/room/status/', content: { shutdown: 'hasStarted', duration: Room.ShutdownPromptTimer.SecondsToCount }) + //} /// /// @@ -558,10 +428,12 @@ private void ShutdownPromptTimer_HasStarted(object sender, EventArgs e) /// private void IsWarmingUpFeedback_OutputChange(object sender, FeedbackEventArgs e) { - var state = new RoomStateMessage(); + var state = new + { + isWarmingUp = e.BoolValue + }; - state.IsWarmingUp = e.BoolValue; - PostStatusMessage(state); + PostStatusMessage(JToken.FromObject(state)); } /// @@ -571,10 +443,11 @@ private void IsWarmingUpFeedback_OutputChange(object sender, FeedbackEventArgs e /// private void IsCoolingDownFeedback_OutputChange(object sender, FeedbackEventArgs e) { - var state = new RoomStateMessage(); - - state.IsCoolingDown = e.BoolValue; - PostStatusMessage(state); + var state = new + { + isCoolingDown = e.BoolValue + }; + PostStatusMessage(JToken.FromObject(state)); } /// @@ -584,10 +457,11 @@ private void IsCoolingDownFeedback_OutputChange(object sender, FeedbackEventArgs /// private void OnFeedback_OutputChange(object sender, FeedbackEventArgs e) { - var state = new RoomStateMessage(); - - state.IsOn = e.BoolValue; - PostStatusMessage(state); + var state = new + { + isOn = e.BoolValue + }; + PostStatusMessage(JToken.FromObject(state)); } private void Room_CurrentVolumeDeviceChange(object sender, VolumeDeviceChangeEventArgs e) @@ -614,9 +488,10 @@ private void MuteFeedback_OutputChange(object sender, FeedbackEventArgs e) { var state = new RoomStateMessage(); - var volumes = new Volumes(); - - volumes.Master = new Volume("master", e.BoolValue); + var volumes = new Dictionary + { + { "master", new Volume("master", e.BoolValue) } + }; state.Volumes = volumes; @@ -628,15 +503,15 @@ private void MuteFeedback_OutputChange(object sender, FeedbackEventArgs e) /// private void VolumeLevelFeedback_OutputChange(object sender, FeedbackEventArgs e) { - var state = new RoomStateMessage(); - - var volumes = new Volumes(); - - volumes.Master = new Volume("master", e.IntValue); - state.Volumes = volumes; - - PostStatusMessage(state); + var state = new + { + volumes = new Dictionary + { + { "master", new Volume("master", e.IntValue) } + } + }; + PostStatusMessage(JToken.FromObject(state)); } @@ -650,67 +525,7 @@ private void Room_CurrentSingleSourceChange(SourceListItem info, ChangeType type    } } */ - if (type == ChangeType.WillChange) - { - // Disconnect from previous source - - if (info != null) - { - var previousDev = info.SourceDevice; - - // device type interfaces - if (previousDev is ISetTopBoxControls) - (previousDev as ISetTopBoxControls).UnlinkActions(Parent); - // common interfaces - if (previousDev is IChannel) - (previousDev as IChannel).UnlinkActions(Parent); - if (previousDev is IColor) - (previousDev as IColor).UnlinkActions(Parent); - if (previousDev is IDPad) - (previousDev as IDPad).UnlinkActions(Parent); - if (previousDev is IDvr) - (previousDev as IDvr).UnlinkActions(Parent); - if (previousDev is INumericKeypad) - (previousDev as INumericKeypad).UnlinkActions(Parent); - if (previousDev is IHasPowerControl) - (previousDev as IHasPowerControl).UnlinkActions(Parent); - if (previousDev is ITransport) - (previousDev as ITransport).UnlinkActions(Parent); - } - } - else // did change - { - if (info != null) - { - var dev = info.SourceDevice; - - if (dev is ISetTopBoxControls) - (dev as ISetTopBoxControls).LinkActions(Parent); - if (dev is IChannel) - (dev as IChannel).LinkActions(Parent); - if (dev is IColor) - (dev as IColor).LinkActions(Parent); - if (dev is IDPad) - (dev as IDPad).LinkActions(Parent); - if (dev is IDvr) - (dev as IDvr).LinkActions(Parent); - if (dev is INumericKeypad) - (dev as INumericKeypad).LinkActions(Parent); - if (dev is IHasPowerControl) - (dev as IHasPowerControl).LinkActions(Parent); - if (dev is ITransport) - (dev as ITransport).LinkActions(Parent); - - var srcRm = Room as IHasCurrentSourceInfoChange; - if (srcRm != null) - { - var state = new RoomStateMessage(); - - state.SelectedSourceKey = srcRm.CurrentSourceInfoKey; - PostStatusMessage(state); - } - } - } + } /// @@ -720,7 +535,8 @@ private void Room_CurrentSingleSourceChange(SourceListItem info, ChangeType type private void SendFullStatusForClientId(string id, IEssentialsRoom room) { //Parent.SendMessageObject(GetFullStatus(room)); - PostStatusMessage(GetFullStatusForClientId(id, room)); + var message = GetFullStatusForClientId(room); + PostStatusMessage(message, id); } @@ -729,54 +545,46 @@ private void SendFullStatusForClientId(string id, IEssentialsRoom room) /// /// The room to get status of /// The status response message - MobileControlResponseMessage GetFullStatusForClientId(string id, IEssentialsRoom room) + private RoomStateMessage GetFullStatusForClientId(IEssentialsRoom room) { Debug.Console(2, this, "GetFullStatus"); var sourceKey = room is IHasCurrentSourceInfoChange ? (room as IHasCurrentSourceInfoChange).CurrentSourceInfoKey : null; - var rmVc = room as IHasCurrentVolumeControls; - var volumes = new Volumes(); - if (rmVc != null) + var volumes = new Dictionary(); + if (room is IHasCurrentVolumeControls rmVc) { - var vc = rmVc.CurrentVolumeControls as IBasicVolumeWithFeedback; - if (vc != null) + if (rmVc.CurrentVolumeControls is IBasicVolumeWithFeedback vc) { - volumes.Master = new Volume("master", vc.VolumeLevelFeedback.UShortValue, vc.MuteFeedback.BoolValue, "Volume", true, ""); - - var privacyRoom = room as IPrivacy; - if (privacyRoom != null) + var volume = new Volume("master", vc.VolumeLevelFeedback.UShortValue, vc.MuteFeedback.BoolValue, "Volume", true, ""); + if (room is IPrivacy privacyRoom) { - volumes.Master.HasPrivacyMute = true; - volumes.Master.PrivacyMuted = privacyRoom.PrivacyModeIsOnFeedback.BoolValue; + volume.HasPrivacyMute = true; + volume.PrivacyMuted = privacyRoom.PrivacyModeIsOnFeedback.BoolValue; } + + volumes.Add("master", volume); + } } - var state = new RoomStateMessage(); - - state.Configuration = GetRoomConfiguration(room); - state.ActivityMode = 1; - state.IsOn = room.OnFeedback.BoolValue; - state.SelectedSourceKey = sourceKey; - state.Volumes = volumes; - state.IsWarmingUp = room.IsWarmingUpFeedback.BoolValue; - state.IsCoolingDown = room.IsCoolingDownFeedback.BoolValue; + var state = new RoomStateMessage + { + Configuration = GetRoomConfiguration(room), + ActivityMode = 1, + IsOn = room.OnFeedback.BoolValue, + SelectedSourceKey = sourceKey, + Volumes = volumes, + IsWarmingUp = room.IsWarmingUpFeedback.BoolValue, + IsCoolingDown = room.IsCoolingDownFeedback.BoolValue + }; - var vtcRoom = room as IEssentialsHuddleVtc1Room; - if (vtcRoom != null) + if (room is IEssentialsHuddleVtc1Room vtcRoom) { state.IsInCall = vtcRoom.InCallFeedback.BoolValue; } - var messageObject = new MobileControlResponseMessage - { - Type = MessagePath, - ClientId = id, - Content = state - }; - - return messageObject; + return state; } /// @@ -785,108 +593,165 @@ MobileControlResponseMessage GetFullStatusForClientId(string id, IEssentialsRoom /// private RoomConfiguration GetRoomConfiguration(IEssentialsRoom room) { - var configuration = new RoomConfiguration(); + var configuration = new RoomConfiguration + { + //ShutdownPromptSeconds = room.ShutdownPromptSeconds, + TouchpanelKeys = DeviceManager.AllDevices. + OfType() + .Where((tp) => tp.DefaultRoomKey.Equals(room.Key, StringComparison.InvariantCultureIgnoreCase)) + .Select(tp => tp.Key).ToList() + }; + + + try + { + var zrcTp = DeviceManager.AllDevices.OfType().SingleOrDefault((tp) => tp.ZoomRoomController); + + configuration.ZoomRoomControllerKey = zrcTp != null ? zrcTp.Key : room.Key; + } + catch + { + configuration.ZoomRoomControllerKey = room.Key; + } + + if (room is IEssentialsRoomPropertiesConfig propertiesConfig) + { + configuration.HelpMessage = propertiesConfig.PropertiesConfig.HelpMessageForDisplay; + } - var huddleRoom = room as IEssentialsHuddleSpaceRoom; - if (huddleRoom != null && !string.IsNullOrEmpty(huddleRoom.PropertiesConfig.HelpMessageForDisplay)) + if (room is IEssentialsHuddleSpaceRoom huddleRoom && !string.IsNullOrEmpty(huddleRoom.PropertiesConfig.HelpMessageForDisplay)) { + Debug.Console(2, this, "Getting huddle room config"); configuration.HelpMessage = huddleRoom.PropertiesConfig.HelpMessageForDisplay; configuration.UiBehavior = huddleRoom.PropertiesConfig.UiBehavior; configuration.DefaultPresentationSourceKey = huddleRoom.PropertiesConfig.DefaultSourceItem; } - var vtc1Room = room as IEssentialsHuddleVtc1Room; - if (vtc1Room != null && !string.IsNullOrEmpty(vtc1Room.PropertiesConfig.HelpMessageForDisplay)) + if (room is IEssentialsHuddleVtc1Room vtc1Room && !string.IsNullOrEmpty(vtc1Room.PropertiesConfig.HelpMessageForDisplay)) { + Debug.Console(2, this, "Getting vtc room config"); configuration.HelpMessage = vtc1Room.PropertiesConfig.HelpMessageForDisplay; configuration.UiBehavior = vtc1Room.PropertiesConfig.UiBehavior; configuration.DefaultPresentationSourceKey = vtc1Room.PropertiesConfig.DefaultSourceItem; } - var techRoom = room as EssentialsTechRoom; - if (techRoom != null && !string.IsNullOrEmpty(techRoom.PropertiesConfig.HelpMessage)) + if (room is IEssentialsTechRoom techRoom && !string.IsNullOrEmpty(techRoom.PropertiesConfig.HelpMessage)) { + Debug.Console(2, this, "Getting tech room config"); configuration.HelpMessage = techRoom.PropertiesConfig.HelpMessage; } - var vcRoom = room as IHasVideoCodec; - if (vcRoom != null) + if (room is IHasVideoCodec vcRoom) { if (vcRoom.VideoCodec != null) { + Debug.Console(2, this, "Getting codec config"); + var type = vcRoom.VideoCodec.GetType(); + configuration.HasVideoConferencing = true; configuration.VideoCodecKey = vcRoom.VideoCodec.Key; - configuration.VideoCodecIsZoomRoom = vcRoom.VideoCodec is Essentials.Devices.Common.VideoCodec.ZoomRoom.ZoomRoom; + configuration.VideoCodecIsZoomRoom = type.Name.Equals("ZoomRoom", StringComparison.InvariantCultureIgnoreCase); } }; - var acRoom = room as IHasAudioCodec; - if (acRoom != null) + if (room is IHasAudioCodec acRoom) { if (acRoom.AudioCodec != null) { + Debug.Console(2, this, "Getting audio codec config"); configuration.HasAudioConferencing = true; configuration.AudioCodecKey = acRoom.AudioCodec.Key; } } - var envRoom = room as IEnvironmentalControls; + + if (room is IHasMatrixRouting matrixRoutingRoom) + { + Debug.Console(2, this, "Getting matrix routing config"); + configuration.MatrixRoutingKey = matrixRoutingRoom.MatrixRoutingDeviceKey; + configuration.EndpointKeys = matrixRoutingRoom.EndpointKeys; + } + + if (room is IEnvironmentalControls envRoom) { + Debug.Console(2, this, "Getting environmental controls config. RoomHasEnvironmentalControls: {0}", envRoom.HasEnvironmentalControlDevices); configuration.HasEnvironmentalControls = envRoom.HasEnvironmentalControlDevices; - if(envRoom.HasEnvironmentalControlDevices) + if (envRoom.HasEnvironmentalControlDevices) { + Debug.Console(2, this, "Room Has {0} Environmental Control Devices.", envRoom.EnvironmentalControlDevices.Count); + foreach (var dev in envRoom.EnvironmentalControlDevices) { + Debug.Console(2, this, "Adding environmental device: {0}", dev.Key); + eEnvironmentalDeviceTypes type = eEnvironmentalDeviceTypes.None; - if(dev is Essentials.Core.Lighting.LightingBase) + if (dev is ILightingScenes || dev is Devices.Common.Lighting.LightingBase) { type = eEnvironmentalDeviceTypes.Lighting; } - else if (dev is Essentials.Core.Shades.ShadeBase) + else if (dev is ShadeBase || dev is IShadesOpenCloseStop || dev is IShadesOpenClosePreset) { type = eEnvironmentalDeviceTypes.Shade; } - else if (dev is Essentials.Core.Shades.ShadeController) + else if (dev is IShades) { type = eEnvironmentalDeviceTypes.ShadeController; } + else if (dev is ISwitchedOutput) + { + type = eEnvironmentalDeviceTypes.Relay; + } + + Debug.Console(2, this, "Environmental Device Type: {0}", type); var envDevice = new EnvironmentalDeviceConfiguration(dev.Key, type); configuration.EnvironmentalDevices.Add(envDevice); } } + else + { + Debug.Console(2, this, "**************************** Room Has No Environmental Control Devices"); + } } - var defDisplayRoom = room as IHasDefaultDisplay; - if (defDisplayRoom != null) + if (room is IHasDefaultDisplay defDisplayRoom) { + Debug.Console(2, this, "Getting default display config"); configuration.DefaultDisplayKey = defDisplayRoom.DefaultDisplay.Key; - configuration.DisplayKeys.Add(defDisplayRoom.DefaultDisplay.Key); + configuration.Destinations.Add(eSourceListItemDestinationTypes.defaultDisplay, defDisplayRoom.DefaultDisplay.Key); } - var multiDisplayRoom = room as IHasMultipleDisplays; - if (multiDisplayRoom != null) + if (room is IHasMultipleDisplays multiDisplayRoom) { - foreach(var display in multiDisplayRoom.Displays) + Debug.Console(2, this, "Getting multiple display config"); + + if (multiDisplayRoom.Displays == null) + { + Debug.Console(2, this, "Displays collection is null"); + } + else { - configuration.DisplayKeys.Add(display.Value.Key); + Debug.Console(2, this, "Displays collection exists"); + + configuration.Destinations = multiDisplayRoom.Displays.ToDictionary(kv => kv.Key, kv => kv.Value.Key); } } var sourceList = ConfigReader.ConfigObject.GetSourceListForKey(room.SourceListKey); if (sourceList != null) { + Debug.Console(2, this, "Getting source list config"); configuration.SourceList = sourceList; configuration.HasRoutingControls = true; foreach (var source in sourceList) { - if (source.Value.SourceDevice is PepperDash.Essentials.Devices.Common.IRSetTopBoxBase) + if (source.Value.SourceDevice is Devices.Common.IRSetTopBoxBase) { configuration.HasSetTopBoxControls = true; continue; @@ -899,17 +764,19 @@ private RoomConfiguration GetRoomConfiguration(IEssentialsRoom room) } } - //var cameraDevices = DeviceManager.AllDevices.Where((d) => d is CameraBase); - //if (cameraDevices != null && cameraDevices.Count() > 0) - //{ - // configuration.HasCameraControls = true; - //} + var destinationList = ConfigReader.ConfigObject.GetDestinationListForKey(room.DestinationListKey); + + if(destinationList != null) + { + configuration.DestinationList = destinationList; + } + return configuration; } } - public class RoomStateMessage: DeviceStateMessageBase + public class RoomStateMessage : DeviceStateMessageBase { [JsonProperty("configuration", NullValueHandling = NullValueHandling.Ignore)] public RoomConfiguration Configuration { get; set; } @@ -928,12 +795,9 @@ public class RoomStateMessage: DeviceStateMessageBase public string SelectedSourceKey { get; set; } [JsonProperty("share", NullValueHandling = NullValueHandling.Ignore)] public ShareState Share { get; set; } - [JsonProperty("supportsAdvancedSharing", NullValueHandling = NullValueHandling.Ignore)] - public bool? SupportsAdvancedSharing { get; set; } - [JsonProperty("userCanChangeShareMode", NullValueHandling = NullValueHandling.Ignore)] - public bool? UserCanChangeShareMode { get; set; } + [JsonProperty("volumes", NullValueHandling = NullValueHandling.Ignore)] - public Volumes Volumes { get; set; } + public Dictionary Volumes { get; set; } [JsonProperty("isInCall", NullValueHandling = NullValueHandling.Ignore)] public bool? IsInCall { get; set; } @@ -954,6 +818,9 @@ public class ShareState /// public class RoomConfiguration { + //[JsonProperty("shutdownPromptSeconds", NullValueHandling = NullValueHandling.Ignore)] + //public int? ShutdownPromptSeconds { get; set; } + [JsonProperty("hasVideoConferencing", NullValueHandling = NullValueHandling.Ignore)] public bool? HasVideoConferencing { get; set; } [JsonProperty("videoCodecIsZoomRoom", NullValueHandling = NullValueHandling.Ignore)] @@ -969,18 +836,34 @@ public class RoomConfiguration [JsonProperty("hasRoutingControls", NullValueHandling = NullValueHandling.Ignore)] public bool? HasRoutingControls { get; set; } + [JsonProperty("touchpanelKeys", NullValueHandling = NullValueHandling.Ignore)] + public List TouchpanelKeys { get; set; } + + [JsonProperty("zoomRoomControllerKey", NullValueHandling = NullValueHandling.Ignore)] + public string ZoomRoomControllerKey { get; set; } + + [JsonProperty("videoCodecKey", NullValueHandling = NullValueHandling.Ignore)] public string VideoCodecKey { get; set; } [JsonProperty("audioCodecKey", NullValueHandling = NullValueHandling.Ignore)] public string AudioCodecKey { get; set; } + [JsonProperty("matrixRoutingKey", NullValueHandling = NullValueHandling.Ignore)] + public string MatrixRoutingKey { get; set; } + [JsonProperty("endpointKeys", NullValueHandling = NullValueHandling.Ignore)] + public List EndpointKeys { get; set; } + [JsonProperty("defaultDisplayKey", NullValueHandling = NullValueHandling.Ignore)] public string DefaultDisplayKey { get; set; } - [JsonProperty("displayKeys", NullValueHandling = NullValueHandling.Ignore)] - public List DisplayKeys { get; set; } + [JsonProperty("destinations", NullValueHandling = NullValueHandling.Ignore)] + public Dictionary Destinations { get; set; } [JsonProperty("environmentalDevices", NullValueHandling = NullValueHandling.Ignore)] public List EnvironmentalDevices { get; set; } [JsonProperty("sourceList", NullValueHandling = NullValueHandling.Ignore)] public Dictionary SourceList { get; set; } + + [JsonProperty("destinationList", NullValueHandling = NullValueHandling.Ignore)] + public Dictionary DestinationList { get; set;} + [JsonProperty("defaultPresentationSourceKey", NullValueHandling = NullValueHandling.Ignore)] public string DefaultPresentationSourceKey { get; set; } @@ -988,14 +871,23 @@ public class RoomConfiguration [JsonProperty("helpMessage", NullValueHandling = NullValueHandling.Ignore)] public string HelpMessage { get; set; } + [JsonProperty("techPassword", NullValueHandling = NullValueHandling.Ignore)] + public string TechPassword { get; set; } + [JsonProperty("uiBehavior", NullValueHandling = NullValueHandling.Ignore)] public EssentialsRoomUiBehaviorConfig UiBehavior { get; set; } -public RoomConfiguration() + [JsonProperty("supportsAdvancedSharing", NullValueHandling = NullValueHandling.Ignore)] + public bool? SupportsAdvancedSharing { get; set; } + [JsonProperty("userCanChangeShareMode", NullValueHandling = NullValueHandling.Ignore)] + public bool? UserCanChangeShareMode { get; set; } + + public RoomConfiguration() { - DisplayKeys = new List(); + Destinations = new Dictionary(); EnvironmentalDevices = new List(); SourceList = new Dictionary(); + TouchpanelKeys = new List(); } } @@ -1022,6 +914,16 @@ public enum eEnvironmentalDeviceTypes Lighting, Shade, ShadeController, + Relay, + } + + public class ApiTouchPanelToken + { + [JsonProperty("touchPanels", NullValueHandling = NullValueHandling.Ignore)] + public List TouchPanels { get; set; } = new List(); + + [JsonProperty("userAppUrl", NullValueHandling = NullValueHandling.Ignore)] + public string UserAppUrl { get; set; } = ""; } #if SERIES3 diff --git a/3-series/RoomBridges/MobileControlSIMPLRoomBridge.cs b/3-series/RoomBridges/MobileControlSIMPLRoomBridge.cs index 3e78276..a617200 100644 --- a/3-series/RoomBridges/MobileControlSIMPLRoomBridge.cs +++ b/3-series/RoomBridges/MobileControlSIMPLRoomBridge.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using Crestron.SimplSharp; +using Crestron.SimplSharp; using Crestron.SimplSharp.Reflection; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.EthernetCommunication; @@ -11,15 +9,17 @@ using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Devices.Common.Codec; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Devices.Common.Cameras; +using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Room.Config; -using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using System; +using System.Collections.Generic; namespace PepperDash.Essentials.Room.MobileControl { -// ReSharper disable once InconsistentNaming + // ReSharper disable once InconsistentNaming public class MobileControlSIMPLRoomBridge : MobileControlBridgeBase, IDelayedConfiguration { private const int SupportedDisplayCount = 10; @@ -70,7 +70,7 @@ public override string RoomKey /// /// public MobileControlSIMPLRoomBridge(string key, string name, uint ipId) - : base(key, "/room/room1") + : base(key, "") { Eisc = new ThreeSeriesTcpIpEthernetIntersystemCommunications(ipId, "127.0.0.2", Global.ControlSystem); var reg = Eisc.Register(); @@ -132,16 +132,16 @@ public override bool CustomActivate() //SetupFunctions(); //SetupFeedbacks(); - var atcKey = string.Format("atc-{0}-{1}", Key, Parent.Key); + var atcKey = string.Format("atc-{0}-{1}", Key, Key); _atcMessenger = new SIMPLAtcMessenger(atcKey, Eisc, "/device/audioCodec"); _atcMessenger.RegisterWithAppServer(Parent); - var vtcKey = string.Format("atc-{0}-{1}", Key, Parent.Key); + var vtcKey = string.Format("atc-{0}-{1}", Key, Key); _vtcMessenger = new SIMPLVtcMessenger(vtcKey, Eisc, "/device/videoCodec"); _vtcMessenger.RegisterWithAppServer(Parent); - var drKey = String.Format("directRoute-{0}-{1}", Key, Parent.Key); - _directRouteMessenger = new SimplDirectRouteMessenger(drKey, Eisc, "/room/room1/routing"); + var drKey = string.Format("directRoute-{0}-{1}", Key, Key); + _directRouteMessenger = new SimplDirectRouteMessenger(drKey, Eisc, "/routing"); _directRouteMessenger.RegisterWithAppServer(Parent); CrestronConsole.AddNewConsoleCommand(s => @@ -160,7 +160,7 @@ public override bool CustomActivate() return base.CustomActivate(); } - + private void UseEssentialsConfig() { ConfigIsLoaded = false; @@ -170,17 +170,13 @@ private void UseEssentialsConfig() Debug.Console(0, this, "******* ESSENTIALS CONFIG: \r{0}", JsonConvert.SerializeObject(ConfigReader.ConfigObject, Formatting.Indented)); - var handler = ConfigurationIsReady; - if (handler != null) - { - handler(this, new EventArgs()); - } + ConfigurationIsReady?.Invoke(this, new EventArgs()); ConfigIsLoaded = true; } #if SERIES4 - protected override void CustomRegisterWithAppServer(IMobileControl3 appServerController) + protected override void RegisterActions() #else protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) #endif @@ -194,32 +190,38 @@ protected override void CustomRegisterWithAppServer(MobileControlSystemControlle /// private void SetupFunctions() { - Parent.AddAction(@"/room/room1/promptForCode", - new Action(() => Eisc.PulseBool(JoinMap.PromptForCode.JoinNumber))); - Parent.AddAction(@"/room/room1/clientJoined", - new Action(() => Eisc.PulseBool(JoinMap.ClientJoined.JoinNumber))); + AddAction(@"/promptForCode", + (id, content) => Eisc.PulseBool(JoinMap.PromptForCode.JoinNumber)); + AddAction(@"/clientJoined", (id, content) => Eisc.PulseBool(JoinMap.ClientJoined.JoinNumber)); - Parent.AddAction(@"/room/room1/status", new Action(SendFullStatus)); + AddAction(@"/status", (id, content) => SendFullStatus()); - Parent.AddAction(@"/room/room1/source", new Action(c => + AddAction(@"/source", (id, content) => { - Eisc.SetString(JoinMap.CurrentSourceKey.JoinNumber, c.SourceListItem); + var msg = content.ToObject(); + + Eisc.SetString(JoinMap.CurrentSourceKey.JoinNumber, msg.SourceListItemKey); Eisc.PulseBool(JoinMap.SourceHasChanged.JoinNumber); - })); + }); - Parent.AddAction(@"/room/room1/defaultsource", new Action(() => - Eisc.PulseBool(JoinMap.ActivityShare.JoinNumber))); - Parent.AddAction(@"/room/room1/activityPhone", new Action(() => - Eisc.PulseBool(JoinMap.ActivityPhoneCall.JoinNumber))); - Parent.AddAction(@"/room/room1/activityVideo", new Action(() => - Eisc.PulseBool(JoinMap.ActivityVideoCall.JoinNumber))); + AddAction(@"/defaultsource", (id, content) => + Eisc.PulseBool(JoinMap.ActivityShare.JoinNumber)); + AddAction(@"/activityPhone", (id, content) => + Eisc.PulseBool(JoinMap.ActivityPhoneCall.JoinNumber)); + AddAction(@"/activityVideo", (id, content) => + Eisc.PulseBool(JoinMap.ActivityVideoCall.JoinNumber)); - Parent.AddAction(@"/room/room1/volumes/master/level", new Action(u => - Eisc.SetUshort(JoinMap.MasterVolume.JoinNumber, u))); - Parent.AddAction(@"/room/room1/volumes/master/muteToggle", new Action(() => - Eisc.PulseBool(JoinMap.MasterVolume.JoinNumber))); - Parent.AddAction(@"/room/room1/volumes/master/privacyMuteToggle", new Action(() => - Eisc.PulseBool(JoinMap.PrivacyMute.JoinNumber))); + AddAction(@"/volumes/master/level", (id, content) => + { + var value = content["value"].Value(); + + Eisc.SetUshort(JoinMap.MasterVolume.JoinNumber, value); + }); + + AddAction(@"/volumes/master/muteToggle", (id, content) => + Eisc.PulseBool(JoinMap.MasterVolume.JoinNumber)); + AddAction(@"/volumes/master/privacyMuteToggle", (id, content) => + Eisc.PulseBool(JoinMap.PrivacyMute.JoinNumber)); // /xyzxyz/volumes/master/muteToggle ---> BoolInput[1] @@ -230,18 +232,22 @@ private void SetupFunctions() for (uint i = volumeStart; i <= volumeEnd; i++) { var index = i; - Parent.AddAction(string.Format(@"/room/room1/volumes/level-{0}/level", index), new Action(u => - Eisc.SetUshort(index, u))); - Parent.AddAction(string.Format(@"/room/room1/volumes/level-{0}/muteToggle", index), new Action(() => - Eisc.PulseBool(index))); + AddAction(string.Format(@"/volumes/level-{0}/level", index), (id, content) => + { + var value = content["value"].Value(); + Eisc.SetUshort(index, value); + }); + + AddAction(string.Format(@"/volumes/level-{0}/muteToggle", index), (id, content) => + Eisc.PulseBool(index)); } - Parent.AddAction(@"/room/room1/shutdownStart", new Action(() => - Eisc.PulseBool(JoinMap.ShutdownStart.JoinNumber))); - Parent.AddAction(@"/room/room1/shutdownEnd", new Action(() => - Eisc.PulseBool(JoinMap.ShutdownEnd.JoinNumber))); - Parent.AddAction(@"/room/room1/shutdownCancel", new Action(() => - Eisc.PulseBool(JoinMap.ShutdownCancel.JoinNumber))); + AddAction(@"/shutdownStart", (id, content) => + Eisc.PulseBool(JoinMap.ShutdownStart.JoinNumber)); + AddAction(@"/shutdownEnd", (id, content) => + Eisc.PulseBool(JoinMap.ShutdownEnd.JoinNumber)); + AddAction(@"/shutdownCancel", (id, content) => + Eisc.PulseBool(JoinMap.ShutdownCancel.JoinNumber)); } @@ -258,11 +264,28 @@ private void SetupSourceFunctions(string devKey) foreach (var item in sourceJoinMap) { var join = item.Value; - Parent.AddAction(string.Format("{0}{1}", prefix, item.Key), - new PressAndHoldAction(b => Eisc.SetBool(join, b))); + AddAction(string.Format("{0}{1}", prefix, item.Key), (id, content) => + { + HandlePressAndHoldEisc(content, b => Eisc.SetBool(join, b)); + }); } } + private void HandlePressAndHoldEisc(JToken content, Action action) + { + var state = content.ToObject>(); + + var timerHandler = PressAndHoldHandler.GetPressAndHoldHandler(state.Value); + if (timerHandler == null) + { + return; + } + + timerHandler(state.Value, action); + + action(state.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase)); + } + /// /// Links feedbacks to whatever is gonna happen! @@ -331,7 +354,7 @@ private void SetupFeedbacks() Eisc.SetUShortSigAction(index, u => // start at join 2 { // need a dict in order to create the level-n property on auxFaders - var dict = new Dictionary {{"level-" + index, new {level = u}}}; + var dict = new Dictionary { { "level-" + index, new { level = u } } }; PostStatus(new { volumes = new @@ -343,7 +366,7 @@ private void SetupFeedbacks() Eisc.SetBoolSigAction(index, b => { // need a dict in order to create the level-n property on auxFaders - var dict = new Dictionary {{"level-" + index, new {muted = b}}}; + var dict = new Dictionary { { "level-" + index, new { muted = b } } }; PostStatus(new { volumes = new @@ -365,17 +388,17 @@ private void SetupFeedbacks() // shutdown things Eisc.SetSigTrueAction(JoinMap.ShutdownCancel.JoinNumber, () => - PostMessage("/room/room1/shutdown/", new + PostMessage("/shutdown/", new { state = "wasCancelled" })); Eisc.SetSigTrueAction(JoinMap.ShutdownEnd.JoinNumber, () => - PostMessage("/room/room1/shutdown/", new + PostMessage("/shutdown/", new { state = "hasFinished" })); Eisc.SetSigTrueAction(JoinMap.ShutdownStart.JoinNumber, () => - PostMessage("/room/room1/shutdown/", new + PostMessage("/shutdown/", new { state = "hasStarted", duration = Eisc.UShortOutput[JoinMap.ShutdownPromptDuration.JoinNumber].UShortValue @@ -389,7 +412,7 @@ private void SetupFeedbacks() Eisc.SetSigTrueAction(JoinMap.ActivityPhoneCall.JoinNumber, () => UpdateActivity(2)); Eisc.SetSigTrueAction(JoinMap.ActivityVideoCall.JoinNumber, () => UpdateActivity(3)); - Parent.ApiOnlineAndAuthorized.LinkInputSig(Eisc.BooleanInput[JoinMap.ApiOnlineAndAuthorized.JoinNumber]); + AppServerController.ApiOnlineAndAuthorized.LinkInputSig(Eisc.BooleanInput[JoinMap.ApiOnlineAndAuthorized.JoinNumber]); } @@ -443,9 +466,11 @@ private DeviceConfig GetSyntheticSourceDevice(SourceListItem sli, string type, u { if (type.ToLower().Equals("simplcameramessenger")) { - var props = new SimplMessengerPropertiesConfig(); - props.DeviceKey = key; - props.JoinMapKey = ""; + var props = new SimplMessengerPropertiesConfig + { + DeviceKey = key, + JoinMapKey = "" + }; var joinStart = 1000 + (i * 100) + 1; // 1001, 1101, 1201, 1301... etc. props.JoinStart = joinStart; devConf.Properties = JToken.FromObject(props); @@ -465,9 +490,9 @@ private void LoadConfigValues() var co = ConfigReader.ConfigObject; - if (!String.IsNullOrEmpty(Eisc.StringOutput[JoinMap.PortalSystemUrl.JoinNumber].StringValue)) + if (!string.IsNullOrEmpty(Eisc.StringOutput[JoinMap.PortalSystemUrl.JoinNumber].StringValue)) { - Parent.SystemUrl = Eisc.StringOutput[JoinMap.PortalSystemUrl.JoinNumber].StringValue; + ConfigReader.ConfigObject.SystemUrl = Eisc.StringOutput[JoinMap.PortalSystemUrl.JoinNumber].StringValue; } co.Info.RuntimeInfo.AppName = Assembly.GetExecutingAssembly().GetName().Name; @@ -513,7 +538,7 @@ private void LoadConfigValues() // This MAY need a check if (Eisc.BooleanOutput[JoinMap.ActivityPhoneCallEnable.JoinNumber].BoolValue) { - rmProps.AudioCodecKey = "audioCodec"; + rmProps.AudioCodecKey = "audioCodec"; } if (Eisc.BooleanOutput[JoinMap.ActivityVideoCallEnable.JoinNumber].BoolValue) @@ -573,7 +598,7 @@ private void LoadConfigValues() Debug.Console(1, "Source at join {0} does not have a name", JoinMap.SourceNameJoinStart.JoinNumber + i); break; } - + var icon = Eisc.StringOutput[JoinMap.SourceIconJoinStart.JoinNumber + i].StringValue; var key = Eisc.StringOutput[JoinMap.SourceKeyJoinStart.JoinNumber + i].StringValue; @@ -591,7 +616,7 @@ private void LoadConfigValues() { Icon = icon, Name = name, - Order = (int) i + 10, + Order = (int)i + 10, SourceKey = string.IsNullOrEmpty(sourceKey) ? key : sourceKey, // Use the value from the join if defined Type = eSourceListItemType.Route, DisableCodecSharing = disableShare, @@ -621,7 +646,7 @@ private void LoadConfigValues() } } else - { + { co.Devices.Add(syntheticDevice); } } @@ -725,16 +750,12 @@ private void LoadConfigValues() Debug.Console(0, this, "******* CONFIG FROM SIMPL: \r{0}", JsonConvert.SerializeObject(ConfigReader.ConfigObject, Formatting.Indented)); - var handler = ConfigurationIsReady; - if (handler != null) - { - handler(this, new EventArgs()); - } + ConfigurationIsReady?.Invoke(this, new EventArgs()); ConfigIsLoaded = true; } - private DeviceConfig GetSyntheticDestinationDevice(DestinationListItem newDli, string key, string name) + private DeviceConfig GetSyntheticDestinationDevice(string key, string name) { // If not, synthesize the device config var devConf = new DeviceConfig @@ -768,7 +789,7 @@ private void CreateDestinationList(BasicConfig co) continue; } - if (String.IsNullOrEmpty(key)) + if (string.IsNullOrEmpty(key)) { continue; } @@ -778,9 +799,9 @@ private void CreateDestinationList(BasicConfig co) eRoutingSignalType parsedType; try { - parsedType = (eRoutingSignalType) Enum.Parse(typeof (eRoutingSignalType), routeType, true); + parsedType = (eRoutingSignalType)Enum.Parse(typeof(eRoutingSignalType), routeType, true); } - catch + catch { Debug.Console(0, this, "Error parsing destination type: {0}", routeType); parsedType = eRoutingSignalType.AudioVideo; @@ -789,7 +810,7 @@ private void CreateDestinationList(BasicConfig co) var newDli = new DestinationListItem { Name = name, - Order = (int) i, + Order = (int)i, SinkKey = key, SinkType = parsedType, }; @@ -815,7 +836,7 @@ private void CreateDestinationList(BasicConfig co) var existingDev = co.GetDeviceForKey(key); - var syntheticDisplay = GetSyntheticDestinationDevice(newDli, key, name); + var syntheticDisplay = GetSyntheticDestinationDevice(key, name); if (existingDev != null) { @@ -824,7 +845,6 @@ private void CreateDestinationList(BasicConfig co) if (existingDev.Properties.Value(_syntheticDeviceKey)) { Debug.Console(0, this, "Updating previous device config with new values"); - existingDev = syntheticDisplay; } else { @@ -832,7 +852,7 @@ private void CreateDestinationList(BasicConfig co) } } else - { + { co.Devices.Add(syntheticDisplay); } } @@ -846,7 +866,7 @@ private void CreateDestinationList(BasicConfig co) co.DestinationLists["default"] = newDl; } - _directRouteMessenger.RegisterForDestinationPaths(); + _directRouteMessenger.RegisterForDestinationPaths(); } /// @@ -865,7 +885,7 @@ private void SetupDeviceMessengers() var props = JsonConvert.DeserializeObject(device.Properties.ToString()); - var messengerKey = string.Format("device-{0}-{1}", Key, Parent.Key); + var messengerKey = string.Format("device-{0}-{1}", Key, Key); if (DeviceManager.GetDeviceForKey(messengerKey) != null) { @@ -919,7 +939,7 @@ private void SetupDeviceMessengers() { var camDevice = dev as CameraBase; Debug.Console(1, this, "Adding CameraBaseMessenger for device: {0}", dev.Key); - var cameraMessenger = new CameraBaseMessenger(device.Key + "-" + Parent.Key, camDevice, + var cameraMessenger = new CameraBaseMessenger(device.Key + "-" + Key, camDevice, "/device/" + device.Key); DeviceMessengers.Add(device.Key, cameraMessenger); DeviceManager.AddDevice(cameraMessenger); @@ -1020,10 +1040,10 @@ private int GetActivityMode() /// The contents of the content object private void PostStatus(object contentObject) { - Parent.SendMessageObject(new + AppServerController.SendMessageObject(new MobileControlMessage { - type = "/room/room1/status/", - content = contentObject + Type = "/status/", + Content = JToken.FromObject(contentObject) }); } @@ -1034,10 +1054,10 @@ private void PostStatus(object contentObject) /// private void PostMessage(string messageType, object contentObject) { - Parent.SendMessageObject(new + AppServerController.SendMessageObject(new MobileControlMessage { - type = messageType, - content = contentObject + Type = messageType, + Content = JToken.FromObject(contentObject) }); } @@ -1082,7 +1102,7 @@ private Dictionary GetSourceGroupDictionary() }; return d; - } + } /// /// updates the usercode from server @@ -1092,7 +1112,7 @@ protected override void UserCodeChange() Debug.Console(1, this, "Server user code changed: {0}", UserCode); - var qrUrl = string.Format("{0}/api/rooms/{1}/{3}/qr?x={2}", Parent.Host, Parent.SystemUuid, new Random().Next(), "room1" ); + var qrUrl = string.Format("{0}/api/rooms/{1}/{3}/qr?x={2}", AppServerController.Host, AppServerController.SystemUuid, new Random().Next(), "room1"); QrCodeUrl = qrUrl; Debug.Console(1, this, "Server user code changed: {0} - {1}", UserCode, qrUrl); diff --git a/3-series/SIMPLJoinMaps/MobileControlSIMPLRoomJoinMap.cs b/3-series/SIMPLJoinMaps/MobileControlSIMPLRoomJoinMap.cs index 5702e1d..fd6e871 100644 --- a/3-series/SIMPLJoinMaps/MobileControlSIMPLRoomJoinMap.cs +++ b/3-series/SIMPLJoinMaps/MobileControlSIMPLRoomJoinMap.cs @@ -3,11 +3,12 @@ namespace PepperDash.Essentials.AppServer { -// ReSharper disable once InconsistentNaming + // ReSharper disable once InconsistentNaming public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced { - [JoinName("QrCodeUrl")] public JoinDataComplete QrCodeUrl = - new JoinDataComplete(new JoinData {JoinNumber = 403, JoinSpan = 1}, + [JoinName("QrCodeUrl")] + public JoinDataComplete QrCodeUrl = + new JoinDataComplete(new JoinData { JoinNumber = 403, JoinSpan = 1 }, new JoinMetadata { Description = "QR Code URL", @@ -25,8 +26,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("MasterVolume")] public JoinDataComplete MasterVolume = - new JoinDataComplete(new JoinData {JoinNumber = 1, JoinSpan = 1}, + [JoinName("MasterVolume")] + public JoinDataComplete MasterVolume = + new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Master Volume Mute Toggle/FB/Level/Label", @@ -34,8 +36,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.DigitalAnalogSerial }); - [JoinName("VolumeJoinStart")] public JoinDataComplete VolumeJoinStart = - new JoinDataComplete(new JoinData {JoinNumber = 2, JoinSpan = 8}, + [JoinName("VolumeJoinStart")] + public JoinDataComplete VolumeJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 8 }, new JoinMetadata { Description = "Volume Mute Toggle/FB/Level/Label", @@ -43,8 +46,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.DigitalAnalogSerial }); - [JoinName("PrivacyMute")] public JoinDataComplete PrivacyMute = - new JoinDataComplete(new JoinData {JoinNumber = 12, JoinSpan = 1}, + [JoinName("PrivacyMute")] + public JoinDataComplete PrivacyMute = + new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata { Description = "Privacy Mute Toggle/FB", @@ -52,8 +56,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("PromptForCode")] public JoinDataComplete PromptForCode = - new JoinDataComplete(new JoinData {JoinNumber = 41, JoinSpan = 1}, + [JoinName("PromptForCode")] + public JoinDataComplete PromptForCode = + new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, new JoinMetadata { Description = "Prompt User for Code", @@ -61,8 +66,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("ClientJoined")] public JoinDataComplete ClientJoined = - new JoinDataComplete(new JoinData {JoinNumber = 42, JoinSpan = 1}, + [JoinName("ClientJoined")] + public JoinDataComplete ClientJoined = + new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, new JoinMetadata { Description = "Client Joined", @@ -90,8 +96,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("ActivityShare")] public JoinDataComplete ActivityShare = - new JoinDataComplete(new JoinData {JoinNumber = 51, JoinSpan = 1}, + [JoinName("ActivityShare")] + public JoinDataComplete ActivityShare = + new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata { Description = "Activity Share", @@ -99,8 +106,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("ActivityPhoneCall")] public JoinDataComplete ActivityPhoneCall = - new JoinDataComplete(new JoinData {JoinNumber = 52, JoinSpan = 1}, + [JoinName("ActivityPhoneCall")] + public JoinDataComplete ActivityPhoneCall = + new JoinDataComplete(new JoinData { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata { Description = "Activity Phone Call", @@ -108,8 +116,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("ActivityVideoCall")] public JoinDataComplete ActivityVideoCall = - new JoinDataComplete(new JoinData {JoinNumber = 53, JoinSpan = 1}, + [JoinName("ActivityVideoCall")] + public JoinDataComplete ActivityVideoCall = + new JoinDataComplete(new JoinData { JoinNumber = 53, JoinSpan = 1 }, new JoinMetadata { Description = "Activity Video Call", @@ -117,8 +126,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("ShutdownPromptDuration")] public JoinDataComplete ShutdownPromptDuration = - new JoinDataComplete(new JoinData {JoinNumber = 61, JoinSpan = 1}, + [JoinName("ShutdownPromptDuration")] + public JoinDataComplete ShutdownPromptDuration = + new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1 }, new JoinMetadata { Description = "Shutdown Cancel", @@ -126,8 +136,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Analog }); - [JoinName("ShutdownCancel")] public JoinDataComplete ShutdownCancel = - new JoinDataComplete(new JoinData {JoinNumber = 61, JoinSpan = 1}, + [JoinName("ShutdownCancel")] + public JoinDataComplete ShutdownCancel = + new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1 }, new JoinMetadata { Description = "Shutdown Cancel", @@ -135,8 +146,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("ShutdownEnd")] public JoinDataComplete ShutdownEnd = - new JoinDataComplete(new JoinData {JoinNumber = 62, JoinSpan = 1}, + [JoinName("ShutdownEnd")] + public JoinDataComplete ShutdownEnd = + new JoinDataComplete(new JoinData { JoinNumber = 62, JoinSpan = 1 }, new JoinMetadata { Description = "Shutdown End", @@ -144,8 +156,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("ShutdownStart")] public JoinDataComplete ShutdownStart = - new JoinDataComplete(new JoinData {JoinNumber = 63, JoinSpan = 1}, + [JoinName("ShutdownStart")] + public JoinDataComplete ShutdownStart = + new JoinDataComplete(new JoinData { JoinNumber = 63, JoinSpan = 1 }, new JoinMetadata { Description = "Shutdown Start", @@ -153,8 +166,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("SourceHasChanged")] public JoinDataComplete SourceHasChanged = - new JoinDataComplete(new JoinData {JoinNumber = 71, JoinSpan = 1}, + [JoinName("SourceHasChanged")] + public JoinDataComplete SourceHasChanged = + new JoinDataComplete(new JoinData { JoinNumber = 71, JoinSpan = 1 }, new JoinMetadata { Description = "Source Changed", @@ -162,8 +176,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("CurrentSourceKey")] public JoinDataComplete CurrentSourceKey = - new JoinDataComplete(new JoinData {JoinNumber = 71, JoinSpan = 1}, + [JoinName("CurrentSourceKey")] + public JoinDataComplete CurrentSourceKey = + new JoinDataComplete(new JoinData { JoinNumber = 71, JoinSpan = 1 }, new JoinMetadata { Description = "Key of selected source", @@ -172,8 +187,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced }); - [JoinName("ConfigIsLocal")] public JoinDataComplete ConfigIsLocal = - new JoinDataComplete(new JoinData {JoinNumber = 100, JoinSpan = 1}, + [JoinName("ConfigIsLocal")] + public JoinDataComplete ConfigIsLocal = + new JoinDataComplete(new JoinData { JoinNumber = 100, JoinSpan = 1 }, new JoinMetadata { Description = "Config is local to Essentials", @@ -181,8 +197,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("NumberOfAuxFaders")] public JoinDataComplete NumberOfAuxFaders = - new JoinDataComplete(new JoinData {JoinNumber = 101, JoinSpan = 1}, + [JoinName("NumberOfAuxFaders")] + public JoinDataComplete NumberOfAuxFaders = + new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata { Description = "Number of Auxilliary Faders", @@ -190,8 +207,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Analog }); - [JoinName("SpeedDialNameStartJoin")] public JoinDataComplete SpeedDialNameStartJoin = - new JoinDataComplete(new JoinData {JoinNumber = 241, JoinSpan = 10}, + [JoinName("SpeedDialNameStartJoin")] + public JoinDataComplete SpeedDialNameStartJoin = + new JoinDataComplete(new JoinData { JoinNumber = 241, JoinSpan = 10 }, new JoinMetadata { Description = "Speed Dial names", @@ -199,8 +217,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("SpeedDialNumberStartJoin")] public JoinDataComplete SpeedDialNumberStartJoin = - new JoinDataComplete(new JoinData {JoinNumber = 251, JoinSpan = 10}, + [JoinName("SpeedDialNumberStartJoin")] + public JoinDataComplete SpeedDialNumberStartJoin = + new JoinDataComplete(new JoinData { JoinNumber = 251, JoinSpan = 10 }, new JoinMetadata { Description = "Speed Dial numbers", @@ -208,8 +227,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("SpeedDialVisibleStartJoin")] public JoinDataComplete SpeedDialVisibleStartJoin = - new JoinDataComplete(new JoinData {JoinNumber = 261, JoinSpan = 10}, + [JoinName("SpeedDialVisibleStartJoin")] + public JoinDataComplete SpeedDialVisibleStartJoin = + new JoinDataComplete(new JoinData { JoinNumber = 261, JoinSpan = 10 }, new JoinMetadata { Description = "Speed Dial Visible", @@ -217,8 +237,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("RoomIsOn")] public JoinDataComplete RoomIsOn = - new JoinDataComplete(new JoinData {JoinNumber = 301, JoinSpan = 1}, + [JoinName("RoomIsOn")] + public JoinDataComplete RoomIsOn = + new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 1 }, new JoinMetadata { Description = "Room Is On", @@ -226,8 +247,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("UserCodeToSystem")] public JoinDataComplete UserCodeToSystem = - new JoinDataComplete(new JoinData {JoinNumber = 401, JoinSpan = 1}, + [JoinName("UserCodeToSystem")] + public JoinDataComplete UserCodeToSystem = + new JoinDataComplete(new JoinData { JoinNumber = 401, JoinSpan = 1 }, new JoinMetadata { Description = "User Code", @@ -235,8 +257,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("ServerUrl")] public JoinDataComplete ServerUrl = - new JoinDataComplete(new JoinData {JoinNumber = 402, JoinSpan = 1}, + [JoinName("ServerUrl")] + public JoinDataComplete ServerUrl = + new JoinDataComplete(new JoinData { JoinNumber = 402, JoinSpan = 1 }, new JoinMetadata { Description = "Server URL", @@ -244,8 +267,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("ConfigRoomName")] public JoinDataComplete ConfigRoomName = - new JoinDataComplete(new JoinData {JoinNumber = 501, JoinSpan = 1}, + [JoinName("ConfigRoomName")] + public JoinDataComplete ConfigRoomName = + new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 1 }, new JoinMetadata { Description = "Room Name", @@ -253,8 +277,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("ConfigHelpMessage")] public JoinDataComplete ConfigHelpMessage = - new JoinDataComplete(new JoinData {JoinNumber = 502, JoinSpan = 1}, + [JoinName("ConfigHelpMessage")] + public JoinDataComplete ConfigHelpMessage = + new JoinDataComplete(new JoinData { JoinNumber = 502, JoinSpan = 1 }, new JoinMetadata { Description = "Room help message", @@ -262,8 +287,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("ConfigHelpNumber")] public JoinDataComplete ConfigHelpNumber = - new JoinDataComplete(new JoinData {JoinNumber = 503, JoinSpan = 1}, + [JoinName("ConfigHelpNumber")] + public JoinDataComplete ConfigHelpNumber = + new JoinDataComplete(new JoinData { JoinNumber = 503, JoinSpan = 1 }, new JoinMetadata { Description = "Room help number", @@ -271,8 +297,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("ConfigRoomPhoneNumber")] public JoinDataComplete ConfigRoomPhoneNumber = - new JoinDataComplete(new JoinData {JoinNumber = 504, JoinSpan = 1}, + [JoinName("ConfigRoomPhoneNumber")] + public JoinDataComplete ConfigRoomPhoneNumber = + new JoinDataComplete(new JoinData { JoinNumber = 504, JoinSpan = 1 }, new JoinMetadata { Description = "Room phone number", @@ -280,8 +307,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("ConfigRoomURI")] public JoinDataComplete ConfigRoomUri = - new JoinDataComplete(new JoinData {JoinNumber = 505, JoinSpan = 1}, + [JoinName("ConfigRoomURI")] + public JoinDataComplete ConfigRoomUri = + new JoinDataComplete(new JoinData { JoinNumber = 505, JoinSpan = 1 }, new JoinMetadata { Description = "Room URI", @@ -299,8 +327,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("ConfigIsReady")] public JoinDataComplete ConfigIsReady = - new JoinDataComplete(new JoinData {JoinNumber = 501, JoinSpan = 1}, + [JoinName("ConfigIsReady")] + public JoinDataComplete ConfigIsReady = + new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 1 }, new JoinMetadata { Description = "Config info from SIMPL is ready", @@ -318,8 +347,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("HideVideoConfRecents")] public JoinDataComplete HideVideoConfRecents = - new JoinDataComplete(new JoinData {JoinNumber = 502, JoinSpan = 1}, + [JoinName("HideVideoConfRecents")] + public JoinDataComplete HideVideoConfRecents = + new JoinDataComplete(new JoinData { JoinNumber = 502, JoinSpan = 1 }, new JoinMetadata { Description = "Hide Video Conference Recents", @@ -327,8 +357,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("ShowCameraWhenNotInCall")] public JoinDataComplete ShowCameraWhenNotInCall = - new JoinDataComplete(new JoinData {JoinNumber = 503, JoinSpan = 1}, + [JoinName("ShowCameraWhenNotInCall")] + public JoinDataComplete ShowCameraWhenNotInCall = + new JoinDataComplete(new JoinData { JoinNumber = 503, JoinSpan = 1 }, new JoinMetadata { Description = "Show camera when not in call", @@ -336,8 +367,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("UseSourceEnabled")] public JoinDataComplete UseSourceEnabled = - new JoinDataComplete(new JoinData {JoinNumber = 504, JoinSpan = 1}, + [JoinName("UseSourceEnabled")] + public JoinDataComplete UseSourceEnabled = + new JoinDataComplete(new JoinData { JoinNumber = 504, JoinSpan = 1 }, new JoinMetadata { Description = "Use Source Enabled Joins", @@ -346,8 +378,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced }); - [JoinName("SourceShareDisableJoinStart")] public JoinDataComplete SourceShareDisableJoinStart = - new JoinDataComplete(new JoinData {JoinNumber = 601, JoinSpan = 20}, + [JoinName("SourceShareDisableJoinStart")] + public JoinDataComplete SourceShareDisableJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 601, JoinSpan = 20 }, new JoinMetadata { Description = "Source is not sharable", @@ -355,8 +388,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("SourceIsEnabledJoinStart")] public JoinDataComplete SourceIsEnabledJoinStart = - new JoinDataComplete(new JoinData {JoinNumber = 621, JoinSpan = 20}, + [JoinName("SourceIsEnabledJoinStart")] + public JoinDataComplete SourceIsEnabledJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 621, JoinSpan = 20 }, new JoinMetadata { Description = "Source is enabled/visible", @@ -385,8 +419,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced }); - [JoinName("SourceNameJoinStart")] public JoinDataComplete SourceNameJoinStart = - new JoinDataComplete(new JoinData {JoinNumber = 601, JoinSpan = 20}, + [JoinName("SourceNameJoinStart")] + public JoinDataComplete SourceNameJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 601, JoinSpan = 20 }, new JoinMetadata { Description = "Source Names", @@ -394,8 +429,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("SourceIconJoinStart")] public JoinDataComplete SourceIconJoinStart = - new JoinDataComplete(new JoinData {JoinNumber = 621, JoinSpan = 20}, + [JoinName("SourceIconJoinStart")] + public JoinDataComplete SourceIconJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 621, JoinSpan = 20 }, new JoinMetadata { Description = "Source Icons", @@ -403,8 +439,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("SourceKeyJoinStart")] public JoinDataComplete SourceKeyJoinStart = - new JoinDataComplete(new JoinData {JoinNumber = 641, JoinSpan = 20}, + [JoinName("SourceKeyJoinStart")] + public JoinDataComplete SourceKeyJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 641, JoinSpan = 20 }, new JoinMetadata { Description = "Source Keys", @@ -422,8 +459,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("SourceTypeJoinStart")] public JoinDataComplete SourceTypeJoinStart = - new JoinDataComplete(new JoinData {JoinNumber = 661, JoinSpan = 20}, + [JoinName("SourceTypeJoinStart")] + public JoinDataComplete SourceTypeJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 661, JoinSpan = 20 }, new JoinMetadata { Description = "Source Types", @@ -431,8 +469,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("CameraNearNameStart")] public JoinDataComplete CameraNearNameStart = - new JoinDataComplete(new JoinData {JoinNumber = 761, JoinSpan = 10}, + [JoinName("CameraNearNameStart")] + public JoinDataComplete CameraNearNameStart = + new JoinDataComplete(new JoinData { JoinNumber = 761, JoinSpan = 10 }, new JoinMetadata { Description = "Near End Camera Names", @@ -440,8 +479,9 @@ public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("CameraFarName")] public JoinDataComplete CameraFarName = - new JoinDataComplete(new JoinData {JoinNumber = 771, JoinSpan = 1}, + [JoinName("CameraFarName")] + public JoinDataComplete CameraFarName = + new JoinDataComplete(new JoinData { JoinNumber = 771, JoinSpan = 1 }, new JoinMetadata { Description = "Far End Camera Name", diff --git a/3-series/SIMPLJoinMaps/MobileControlSIMPLRunDirectRouteActionJoinMap.cs b/3-series/SIMPLJoinMaps/MobileControlSIMPLRunDirectRouteActionJoinMap.cs index ef906ee..10c516e 100644 --- a/3-series/SIMPLJoinMaps/MobileControlSIMPLRunDirectRouteActionJoinMap.cs +++ b/3-series/SIMPLJoinMaps/MobileControlSIMPLRunDirectRouteActionJoinMap.cs @@ -1,9 +1,8 @@ -using System; -using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer { - public class MobileControlSIMPLRunDirectRouteActionJoinMap:JoinMapBaseAdvanced + public class MobileControlSIMPLRunDirectRouteActionJoinMap : JoinMapBaseAdvanced { [JoinName("AdvancedSharingModeFb")] public JoinDataComplete AdvancedSharingModeFb = @@ -57,7 +56,7 @@ public class MobileControlSIMPLRunDirectRouteActionJoinMap:JoinMapBaseAdvanced [JoinName("SourceForDestinationAudio")] public JoinDataComplete SourceForDestinationAudio = - new JoinDataComplete(new JoinData {JoinNumber = 61, JoinSpan = 1}, + new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1 }, new JoinMetadata { Description = "Source to Route to Destination & FB", diff --git a/3-series/SIMPLJoinMaps/SIMPLAtcJoinMap.cs b/3-series/SIMPLJoinMaps/SIMPLAtcJoinMap.cs index 56bc1c2..0ec4de5 100644 --- a/3-series/SIMPLJoinMaps/SIMPLAtcJoinMap.cs +++ b/3-series/SIMPLJoinMaps/SIMPLAtcJoinMap.cs @@ -5,8 +5,9 @@ namespace PepperDash.Essentials.AppServer { public class SIMPLAtcJoinMap : JoinMapBaseAdvanced { - [JoinName("EndCall")] public JoinDataComplete EndCall = - new JoinDataComplete(new JoinData() {JoinNumber = 21, JoinSpan = 1}, + [JoinName("EndCall")] + public JoinDataComplete EndCall = + new JoinDataComplete(new JoinData() { JoinNumber = 21, JoinSpan = 1 }, new JoinMetadata() { Description = "Hang Up", @@ -14,8 +15,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("IncomingAnswer")] public JoinDataComplete IncomingAnswer = - new JoinDataComplete(new JoinData() {JoinNumber = 51, JoinSpan = 1}, + [JoinName("IncomingAnswer")] + public JoinDataComplete IncomingAnswer = + new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata() { Description = "Answer Incoming Call", @@ -23,8 +25,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("IncomingReject")] public JoinDataComplete IncomingReject = - new JoinDataComplete(new JoinData() {JoinNumber = 52, JoinSpan = 1}, + [JoinName("IncomingReject")] + public JoinDataComplete IncomingReject = + new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata() { Description = "Reject Incoming Call", @@ -32,8 +35,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("SpeedDialStart")] public JoinDataComplete SpeedDialStart = - new JoinDataComplete(new JoinData() {JoinNumber = 41, JoinSpan = 4}, + [JoinName("SpeedDialStart")] + public JoinDataComplete SpeedDialStart = + new JoinDataComplete(new JoinData() { JoinNumber = 41, JoinSpan = 4 }, new JoinMetadata() { Description = "Speed Dial", @@ -41,8 +45,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("CurrentDialString")] public JoinDataComplete CurrentDialString = - new JoinDataComplete(new JoinData() {JoinNumber = 1, JoinSpan = 1}, + [JoinName("CurrentDialString")] + public JoinDataComplete CurrentDialString = + new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Dial String", @@ -50,8 +55,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("CurrentCallNumber")] public JoinDataComplete CurrentCallNumber = - new JoinDataComplete(new JoinData() {JoinNumber = 11, JoinSpan = 1}, + [JoinName("CurrentCallNumber")] + public JoinDataComplete CurrentCallNumber = + new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Call Number", @@ -59,8 +65,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("CurrentCallName")] public JoinDataComplete CurrentCallName = - new JoinDataComplete(new JoinData() {JoinNumber = 12, JoinSpan = 1}, + [JoinName("CurrentCallName")] + public JoinDataComplete CurrentCallName = + new JoinDataComplete(new JoinData() { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Call Name", @@ -68,8 +75,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("HookState")] public JoinDataComplete HookState = - new JoinDataComplete(new JoinData() {JoinNumber = 21, JoinSpan = 1}, + [JoinName("HookState")] + public JoinDataComplete HookState = + new JoinDataComplete(new JoinData() { JoinNumber = 21, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Hook State", @@ -77,8 +85,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("CallDirection")] public JoinDataComplete CallDirection = - new JoinDataComplete(new JoinData() {JoinNumber = 22, JoinSpan = 1}, + [JoinName("CallDirection")] + public JoinDataComplete CallDirection = + new JoinDataComplete(new JoinData() { JoinNumber = 22, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Call Direction", @@ -86,8 +95,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("IncomingCallName")] public JoinDataComplete IncomingCallName = - new JoinDataComplete(new JoinData() {JoinNumber = 51, JoinSpan = 1}, + [JoinName("IncomingCallName")] + public JoinDataComplete IncomingCallName = + new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata() { Description = "Incoming Call Name", @@ -95,8 +105,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("IncomingCallNumber")] public JoinDataComplete IncomingCallNumber = - new JoinDataComplete(new JoinData() {JoinNumber = 52, JoinSpan = 1}, + [JoinName("IncomingCallNumber")] + public JoinDataComplete IncomingCallNumber = + new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata() { Description = "Incoming Call Number", @@ -104,8 +115,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("0")] public JoinDataComplete Dtmf0 = - new JoinDataComplete(new JoinData() {JoinNumber = 10, JoinSpan = 1}, + [JoinName("0")] + public JoinDataComplete Dtmf0 = + new JoinDataComplete(new JoinData() { JoinNumber = 10, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 0", @@ -113,8 +125,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("1")] public JoinDataComplete Dtmf1 = - new JoinDataComplete(new JoinData() {JoinNumber = 1, JoinSpan = 1}, + [JoinName("1")] + public JoinDataComplete Dtmf1 = + new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 1", @@ -122,8 +135,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("2")] public JoinDataComplete Dtmf2 = - new JoinDataComplete(new JoinData() {JoinNumber = 2, JoinSpan = 1}, + [JoinName("2")] + public JoinDataComplete Dtmf2 = + new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 2", @@ -131,8 +145,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("3")] public JoinDataComplete Dtmf3 = - new JoinDataComplete(new JoinData() {JoinNumber = 3, JoinSpan = 1}, + [JoinName("3")] + public JoinDataComplete Dtmf3 = + new JoinDataComplete(new JoinData() { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 3", @@ -140,8 +155,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("4")] public JoinDataComplete Dtmf4 = - new JoinDataComplete(new JoinData() {JoinNumber = 4, JoinSpan = 1}, + [JoinName("4")] + public JoinDataComplete Dtmf4 = + new JoinDataComplete(new JoinData() { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 4", @@ -149,8 +165,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("5")] public JoinDataComplete Dtmf5 = - new JoinDataComplete(new JoinData() {JoinNumber = 5, JoinSpan = 1}, + [JoinName("5")] + public JoinDataComplete Dtmf5 = + new JoinDataComplete(new JoinData() { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 5", @@ -158,8 +175,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("6")] public JoinDataComplete Dtmf6 = - new JoinDataComplete(new JoinData() {JoinNumber = 6, JoinSpan = 1}, + [JoinName("6")] + public JoinDataComplete Dtmf6 = + new JoinDataComplete(new JoinData() { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 6", @@ -167,8 +185,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("7")] public JoinDataComplete Dtmf7 = - new JoinDataComplete(new JoinData() {JoinNumber = 7, JoinSpan = 1}, + [JoinName("7")] + public JoinDataComplete Dtmf7 = + new JoinDataComplete(new JoinData() { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 7", @@ -176,8 +195,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("8")] public JoinDataComplete Dtmf8 = - new JoinDataComplete(new JoinData() {JoinNumber = 8, JoinSpan = 1}, + [JoinName("8")] + public JoinDataComplete Dtmf8 = + new JoinDataComplete(new JoinData() { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 8", @@ -185,8 +205,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("9")] public JoinDataComplete Dtmf9 = - new JoinDataComplete(new JoinData() {JoinNumber = 9, JoinSpan = 1}, + [JoinName("9")] + public JoinDataComplete Dtmf9 = + new JoinDataComplete(new JoinData() { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 9", @@ -194,8 +215,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("*")] public JoinDataComplete DtmfStar = - new JoinDataComplete(new JoinData() {JoinNumber = 11, JoinSpan = 1}, + [JoinName("*")] + public JoinDataComplete DtmfStar = + new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF *", @@ -203,8 +225,9 @@ public class SIMPLAtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("#")] public JoinDataComplete DtmfPound = - new JoinDataComplete(new JoinData() {JoinNumber = 12, JoinSpan = 1}, + [JoinName("#")] + public JoinDataComplete DtmfPound = + new JoinDataComplete(new JoinData() { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF #", diff --git a/3-series/SIMPLJoinMaps/SIMPLVtcJoinMap.cs b/3-series/SIMPLJoinMaps/SIMPLVtcJoinMap.cs index ad89fd8..69b3249 100644 --- a/3-series/SIMPLJoinMaps/SIMPLVtcJoinMap.cs +++ b/3-series/SIMPLJoinMaps/SIMPLVtcJoinMap.cs @@ -5,8 +5,9 @@ namespace PepperDash.Essentials.AppServer { public class SIMPLVtcJoinMap : JoinMapBaseAdvanced { - [JoinName("EndCall")] public JoinDataComplete EndCall = - new JoinDataComplete(new JoinData() {JoinNumber = 24, JoinSpan = 1}, + [JoinName("EndCall")] + public JoinDataComplete EndCall = + new JoinDataComplete(new JoinData() { JoinNumber = 24, JoinSpan = 1 }, new JoinMetadata() { Description = "Hang Up", @@ -14,8 +15,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("IncomingCall")] public JoinDataComplete IncomingCall = - new JoinDataComplete(new JoinData() {JoinNumber = 50, JoinSpan = 1}, + [JoinName("IncomingCall")] + public JoinDataComplete IncomingCall = + new JoinDataComplete(new JoinData() { JoinNumber = 50, JoinSpan = 1 }, new JoinMetadata() { Description = "Incoming Call", @@ -23,8 +25,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("IncomingAnswer")] public JoinDataComplete IncomingAnswer = - new JoinDataComplete(new JoinData() {JoinNumber = 51, JoinSpan = 1}, + [JoinName("IncomingAnswer")] + public JoinDataComplete IncomingAnswer = + new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata() { Description = "Answer Incoming Call", @@ -32,8 +35,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("IncomingReject")] public JoinDataComplete IncomingReject = - new JoinDataComplete(new JoinData() {JoinNumber = 52, JoinSpan = 1}, + [JoinName("IncomingReject")] + public JoinDataComplete IncomingReject = + new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata() { Description = "Reject Incoming Call", @@ -41,8 +45,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("SpeedDialStart")] public JoinDataComplete SpeedDialStart = - new JoinDataComplete(new JoinData() {JoinNumber = 41, JoinSpan = 4}, + [JoinName("SpeedDialStart")] + public JoinDataComplete SpeedDialStart = + new JoinDataComplete(new JoinData() { JoinNumber = 41, JoinSpan = 4 }, new JoinMetadata() { Description = "Speed Dial", @@ -50,8 +55,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("DirectorySearchBusy")] public JoinDataComplete DirectorySearchBusy = - new JoinDataComplete(new JoinData() {JoinNumber = 100, JoinSpan = 1}, + [JoinName("DirectorySearchBusy")] + public JoinDataComplete DirectorySearchBusy = + new JoinDataComplete(new JoinData() { JoinNumber = 100, JoinSpan = 1 }, new JoinMetadata() { Description = "Directory Search Busy FB", @@ -59,8 +65,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("DirectoryLineSelected")] public JoinDataComplete DirectoryLineSelected = - new JoinDataComplete(new JoinData() {JoinNumber = 101, JoinSpan = 1}, + [JoinName("DirectoryLineSelected")] + public JoinDataComplete DirectoryLineSelected = + new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata() { Description = "Directory Line Selected FB", @@ -68,8 +75,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("DirectoryEntryIsContact")] public JoinDataComplete DirectoryEntryIsContact = - new JoinDataComplete(new JoinData() {JoinNumber = 101, JoinSpan = 1}, + [JoinName("DirectoryEntryIsContact")] + public JoinDataComplete DirectoryEntryIsContact = + new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata() { Description = "Directory Selected Entry Is Contact FB", @@ -77,8 +85,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("DirectoryIsRoot")] public JoinDataComplete DirectoryIsRoot = - new JoinDataComplete(new JoinData() {JoinNumber = 102, JoinSpan = 1}, + [JoinName("DirectoryIsRoot")] + public JoinDataComplete DirectoryIsRoot = + new JoinDataComplete(new JoinData() { JoinNumber = 102, JoinSpan = 1 }, new JoinMetadata() { Description = "Directory is on Root FB", @@ -86,8 +95,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("DDirectoryHasChanged")] public JoinDataComplete DDirectoryHasChanged = - new JoinDataComplete(new JoinData() {JoinNumber = 103, JoinSpan = 1}, + [JoinName("DDirectoryHasChanged")] + public JoinDataComplete DDirectoryHasChanged = + new JoinDataComplete(new JoinData() { JoinNumber = 103, JoinSpan = 1 }, new JoinMetadata() { Description = "Directory has changed FB", @@ -95,8 +105,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("DirectoryRoot")] public JoinDataComplete DirectoryRoot = - new JoinDataComplete(new JoinData() {JoinNumber = 104, JoinSpan = 1}, + [JoinName("DirectoryRoot")] + public JoinDataComplete DirectoryRoot = + new JoinDataComplete(new JoinData() { JoinNumber = 104, JoinSpan = 1 }, new JoinMetadata() { Description = "Go to Directory Root", @@ -104,8 +115,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("DirectoryFolderBack")] public JoinDataComplete DirectoryFolderBack = - new JoinDataComplete(new JoinData() {JoinNumber = 105, JoinSpan = 1}, + [JoinName("DirectoryFolderBack")] + public JoinDataComplete DirectoryFolderBack = + new JoinDataComplete(new JoinData() { JoinNumber = 105, JoinSpan = 1 }, new JoinMetadata() { Description = "Go back one directory level", @@ -113,8 +125,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("DirectoryDialSelectedLine")] public JoinDataComplete DirectoryDialSelectedLine = - new JoinDataComplete(new JoinData() {JoinNumber = 106, JoinSpan = 1}, + [JoinName("DirectoryDialSelectedLine")] + public JoinDataComplete DirectoryDialSelectedLine = + new JoinDataComplete(new JoinData() { JoinNumber = 106, JoinSpan = 1 }, new JoinMetadata() { Description = "Dial selected directory line", @@ -122,8 +135,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("CameraTiltUp")] public JoinDataComplete CameraTiltUp = - new JoinDataComplete(new JoinData() {JoinNumber = 111, JoinSpan = 1}, + [JoinName("CameraTiltUp")] + public JoinDataComplete CameraTiltUp = + new JoinDataComplete(new JoinData() { JoinNumber = 111, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Tilt Up", @@ -131,8 +145,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("CameraTiltDown")] public JoinDataComplete CameraTiltDown = - new JoinDataComplete(new JoinData() {JoinNumber = 112, JoinSpan = 1}, + [JoinName("CameraTiltDown")] + public JoinDataComplete CameraTiltDown = + new JoinDataComplete(new JoinData() { JoinNumber = 112, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Tilt Down", @@ -140,8 +155,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("CameraPanLeft")] public JoinDataComplete CameraPanLeft = - new JoinDataComplete(new JoinData() {JoinNumber = 113, JoinSpan = 1}, + [JoinName("CameraPanLeft")] + public JoinDataComplete CameraPanLeft = + new JoinDataComplete(new JoinData() { JoinNumber = 113, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Pan Left", @@ -149,8 +165,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("CameraPanRight")] public JoinDataComplete CameraPanRight = - new JoinDataComplete(new JoinData() {JoinNumber = 114, JoinSpan = 1}, + [JoinName("CameraPanRight")] + public JoinDataComplete CameraPanRight = + new JoinDataComplete(new JoinData() { JoinNumber = 114, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Pan Right", @@ -158,8 +175,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("CameraZoomIn")] public JoinDataComplete CameraZoomIn = - new JoinDataComplete(new JoinData() {JoinNumber = 115, JoinSpan = 1}, + [JoinName("CameraZoomIn")] + public JoinDataComplete CameraZoomIn = + new JoinDataComplete(new JoinData() { JoinNumber = 115, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Zoom In", @@ -167,8 +185,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("CameraZoomOut")] public JoinDataComplete CameraZoomOut = - new JoinDataComplete(new JoinData() {JoinNumber = 116, JoinSpan = 1}, + [JoinName("CameraZoomOut")] + public JoinDataComplete CameraZoomOut = + new JoinDataComplete(new JoinData() { JoinNumber = 116, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Zoom Out", @@ -176,8 +195,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("CameraPresetStart")] public JoinDataComplete CameraPresetStart = - new JoinDataComplete(new JoinData() {JoinNumber = 121, JoinSpan = 5}, + [JoinName("CameraPresetStart")] + public JoinDataComplete CameraPresetStart = + new JoinDataComplete(new JoinData() { JoinNumber = 121, JoinSpan = 5 }, new JoinMetadata() { Description = "Camera Presets", @@ -185,8 +205,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("CameraModeAuto")] public JoinDataComplete CameraModeAuto = - new JoinDataComplete(new JoinData() {JoinNumber = 131, JoinSpan = 1}, + [JoinName("CameraModeAuto")] + public JoinDataComplete CameraModeAuto = + new JoinDataComplete(new JoinData() { JoinNumber = 131, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Mode Auto", @@ -194,8 +215,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("CameraModeManual")] public JoinDataComplete CameraModeManual = - new JoinDataComplete(new JoinData() {JoinNumber = 132, JoinSpan = 1}, + [JoinName("CameraModeManual")] + public JoinDataComplete CameraModeManual = + new JoinDataComplete(new JoinData() { JoinNumber = 132, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Mode Manual", @@ -203,8 +225,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("CameraModeOff")] public JoinDataComplete CameraModeOff = - new JoinDataComplete(new JoinData() {JoinNumber = 133, JoinSpan = 1}, + [JoinName("CameraModeOff")] + public JoinDataComplete CameraModeOff = + new JoinDataComplete(new JoinData() { JoinNumber = 133, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Mode Off", @@ -212,8 +235,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("CameraSelfView")] public JoinDataComplete CameraSelfView = - new JoinDataComplete(new JoinData() {JoinNumber = 141, JoinSpan = 1}, + [JoinName("CameraSelfView")] + public JoinDataComplete CameraSelfView = + new JoinDataComplete(new JoinData() { JoinNumber = 141, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Self View Toggle/FB", @@ -221,8 +245,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("CameraLayout")] public JoinDataComplete CameraLayout = - new JoinDataComplete(new JoinData() {JoinNumber = 142, JoinSpan = 1}, + [JoinName("CameraLayout")] + public JoinDataComplete CameraLayout = + new JoinDataComplete(new JoinData() { JoinNumber = 142, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Layout Toggle", @@ -230,8 +255,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("CameraSupportsAutoMode")] public JoinDataComplete CameraSupportsAutoMode = - new JoinDataComplete(new JoinData() {JoinNumber = 143, JoinSpan = 1}, + [JoinName("CameraSupportsAutoMode")] + public JoinDataComplete CameraSupportsAutoMode = + new JoinDataComplete(new JoinData() { JoinNumber = 143, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Supports Auto Mode FB", @@ -239,8 +265,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("CameraSupportsOffMode")] public JoinDataComplete CameraSupportsOffMode = - new JoinDataComplete(new JoinData() {JoinNumber = 144, JoinSpan = 1}, + [JoinName("CameraSupportsOffMode")] + public JoinDataComplete CameraSupportsOffMode = + new JoinDataComplete(new JoinData() { JoinNumber = 144, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Supports Off Mode FB", @@ -248,8 +275,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("CameraNumberSelect")] public JoinDataComplete CameraNumberSelect = - new JoinDataComplete(new JoinData() {JoinNumber = 60, JoinSpan = 1}, + [JoinName("CameraNumberSelect")] + public JoinDataComplete CameraNumberSelect = + new JoinDataComplete(new JoinData() { JoinNumber = 60, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Number Select/FB", @@ -257,8 +285,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("DirectorySelectRow")] public JoinDataComplete DirectorySelectRow = - new JoinDataComplete(new JoinData() {JoinNumber = 101, JoinSpan = 1}, + [JoinName("DirectorySelectRow")] + public JoinDataComplete DirectorySelectRow = + new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata() { Description = "Directory Select Row", @@ -266,8 +295,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Analog }); - [JoinName("DirectoryRowCount")] public JoinDataComplete DirectoryRowCount = - new JoinDataComplete(new JoinData() {JoinNumber = 101, JoinSpan = 1}, + [JoinName("DirectoryRowCount")] + public JoinDataComplete DirectoryRowCount = + new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata() { Description = "Directory Row Count FB", @@ -275,8 +305,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Analog }); - [JoinName("CurrentDialString")] public JoinDataComplete CurrentDialString = - new JoinDataComplete(new JoinData() {JoinNumber = 1, JoinSpan = 1}, + [JoinName("CurrentDialString")] + public JoinDataComplete CurrentDialString = + new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Dial String", @@ -284,8 +315,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("CurrentCallName")] public JoinDataComplete CurrentCallName = - new JoinDataComplete(new JoinData() {JoinNumber = 2, JoinSpan = 1}, + [JoinName("CurrentCallName")] + public JoinDataComplete CurrentCallName = + new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Call Name", @@ -293,8 +325,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("CurrentCallNumber")] public JoinDataComplete CurrentCallNumber = - new JoinDataComplete(new JoinData() {JoinNumber = 3, JoinSpan = 1}, + [JoinName("CurrentCallNumber")] + public JoinDataComplete CurrentCallNumber = + new JoinDataComplete(new JoinData() { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Call Number", @@ -302,8 +335,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("HookState")] public JoinDataComplete HookState = - new JoinDataComplete(new JoinData() {JoinNumber = 31, JoinSpan = 1}, + [JoinName("HookState")] + public JoinDataComplete HookState = + new JoinDataComplete(new JoinData() { JoinNumber = 31, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Hook State", @@ -311,8 +345,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("CallDirection")] public JoinDataComplete CallDirection = - new JoinDataComplete(new JoinData() {JoinNumber = 22, JoinSpan = 1}, + [JoinName("CallDirection")] + public JoinDataComplete CallDirection = + new JoinDataComplete(new JoinData() { JoinNumber = 22, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Call Direction", @@ -320,8 +355,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("IncomingCallName")] public JoinDataComplete IncomingCallName = - new JoinDataComplete(new JoinData() {JoinNumber = 51, JoinSpan = 1}, + [JoinName("IncomingCallName")] + public JoinDataComplete IncomingCallName = + new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata() { Description = "Incoming Call Name", @@ -329,8 +365,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("IncomingCallNumber")] public JoinDataComplete IncomingCallNumber = - new JoinDataComplete(new JoinData() {JoinNumber = 52, JoinSpan = 1}, + [JoinName("IncomingCallNumber")] + public JoinDataComplete IncomingCallNumber = + new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata() { Description = "Incoming Call Number", @@ -338,8 +375,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("DirectorySearchString")] public JoinDataComplete DirectorySearchString = - new JoinDataComplete(new JoinData() {JoinNumber = 100, JoinSpan = 1}, + [JoinName("DirectorySearchString")] + public JoinDataComplete DirectorySearchString = + new JoinDataComplete(new JoinData() { JoinNumber = 100, JoinSpan = 1 }, new JoinMetadata() { Description = "Directory Search String", @@ -347,8 +385,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("DirectoryEntriesStart")] public JoinDataComplete DirectoryEntriesStart = - new JoinDataComplete(new JoinData() {JoinNumber = 101, JoinSpan = 255}, + [JoinName("DirectoryEntriesStart")] + public JoinDataComplete DirectoryEntriesStart = + new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 255 }, new JoinMetadata() { Description = "Directory Entries", @@ -356,8 +395,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("DirectoryEntrySelectedName")] public JoinDataComplete DirectoryEntrySelectedName = - new JoinDataComplete(new JoinData() {JoinNumber = 356, JoinSpan = 1}, + [JoinName("DirectoryEntrySelectedName")] + public JoinDataComplete DirectoryEntrySelectedName = + new JoinDataComplete(new JoinData() { JoinNumber = 356, JoinSpan = 1 }, new JoinMetadata() { Description = "Selected Directory Entry Name", @@ -365,8 +405,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("DirectoryEntrySelectedNumber")] public JoinDataComplete DirectoryEntrySelectedNumber = - new JoinDataComplete(new JoinData() {JoinNumber = 357, JoinSpan = 1}, + [JoinName("DirectoryEntrySelectedNumber")] + public JoinDataComplete DirectoryEntrySelectedNumber = + new JoinDataComplete(new JoinData() { JoinNumber = 357, JoinSpan = 1 }, new JoinMetadata() { Description = "Selected Directory Entry Number", @@ -374,8 +415,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("DirectorySelectedFolderName")] public JoinDataComplete DirectorySelectedFolderName = - new JoinDataComplete(new JoinData() {JoinNumber = 358, JoinSpan = 1}, + [JoinName("DirectorySelectedFolderName")] + public JoinDataComplete DirectorySelectedFolderName = + new JoinDataComplete(new JoinData() { JoinNumber = 358, JoinSpan = 1 }, new JoinMetadata() { Description = "Selected Directory Folder Name", @@ -383,8 +425,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Serial }); - [JoinName("1")] public JoinDataComplete Dtmf1 = - new JoinDataComplete(new JoinData() {JoinNumber = 1, JoinSpan = 1}, + [JoinName("1")] + public JoinDataComplete Dtmf1 = + new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 1", @@ -392,8 +435,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("2")] public JoinDataComplete Dtmf2 = - new JoinDataComplete(new JoinData() {JoinNumber = 2, JoinSpan = 1}, + [JoinName("2")] + public JoinDataComplete Dtmf2 = + new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 2", @@ -401,8 +445,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("3")] public JoinDataComplete Dtmf3 = - new JoinDataComplete(new JoinData() {JoinNumber = 3, JoinSpan = 1}, + [JoinName("3")] + public JoinDataComplete Dtmf3 = + new JoinDataComplete(new JoinData() { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 3", @@ -410,8 +455,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("4")] public JoinDataComplete Dtmf4 = - new JoinDataComplete(new JoinData() {JoinNumber = 4, JoinSpan = 1}, + [JoinName("4")] + public JoinDataComplete Dtmf4 = + new JoinDataComplete(new JoinData() { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 4", @@ -419,8 +465,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("5")] public JoinDataComplete Dtmf5 = - new JoinDataComplete(new JoinData() {JoinNumber = 5, JoinSpan = 1}, + [JoinName("5")] + public JoinDataComplete Dtmf5 = + new JoinDataComplete(new JoinData() { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 5", @@ -428,8 +475,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("6")] public JoinDataComplete Dtmf6 = - new JoinDataComplete(new JoinData() {JoinNumber = 6, JoinSpan = 1}, + [JoinName("6")] + public JoinDataComplete Dtmf6 = + new JoinDataComplete(new JoinData() { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 6", @@ -437,8 +485,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("7")] public JoinDataComplete Dtmf7 = - new JoinDataComplete(new JoinData() {JoinNumber = 7, JoinSpan = 1}, + [JoinName("7")] + public JoinDataComplete Dtmf7 = + new JoinDataComplete(new JoinData() { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 7", @@ -446,8 +495,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("8")] public JoinDataComplete Dtmf8 = - new JoinDataComplete(new JoinData() {JoinNumber = 8, JoinSpan = 1}, + [JoinName("8")] + public JoinDataComplete Dtmf8 = + new JoinDataComplete(new JoinData() { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 8", @@ -455,8 +505,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("9")] public JoinDataComplete Dtmf9 = - new JoinDataComplete(new JoinData() {JoinNumber = 9, JoinSpan = 1}, + [JoinName("9")] + public JoinDataComplete Dtmf9 = + new JoinDataComplete(new JoinData() { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 9", @@ -464,8 +515,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("0")] public JoinDataComplete Dtmf0 = - new JoinDataComplete(new JoinData() {JoinNumber = 10, JoinSpan = 1}, + [JoinName("0")] + public JoinDataComplete Dtmf0 = + new JoinDataComplete(new JoinData() { JoinNumber = 10, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 0", @@ -473,8 +525,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("*")] public JoinDataComplete DtmfStar = - new JoinDataComplete(new JoinData() {JoinNumber = 11, JoinSpan = 1}, + [JoinName("*")] + public JoinDataComplete DtmfStar = + new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF *", @@ -482,8 +535,9 @@ public class SIMPLVtcJoinMap : JoinMapBaseAdvanced JoinType = eJoinType.Digital }); - [JoinName("#")] public JoinDataComplete DtmfPound = - new JoinDataComplete(new JoinData() {JoinNumber = 12, JoinSpan = 1}, + [JoinName("#")] + public JoinDataComplete DtmfPound = + new JoinDataComplete(new JoinData() { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF #", diff --git a/3-series/TransmitMessage.cs b/3-series/TransmitMessage.cs index 923cf3b..912d6af 100644 --- a/3-series/TransmitMessage.cs +++ b/3-series/TransmitMessage.cs @@ -42,7 +42,7 @@ public void Dispatch() if (_ws != null && _ws.IsAlive) { var message = JsonConvert.SerializeObject(msgToSend, Formatting.None, - new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = {new IsoDateTimeConverter()} }); + new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new IsoDateTimeConverter() } }); Debug.Console(2, "Message TX: {0}", message); @@ -94,26 +94,26 @@ public MessageToClients(DeviceStateMessageBase msg, MobileControlWebsocketServer public void Dispatch() { try - { + { //Debug.Console(2, "Message: {0}", msgToSend.ToString()); if (_server != null) { Debug.Console(2, _server, Debug.ErrorLogLevel.Notice, "Dispatching message type: {0}", msgToSend.GetType()); - + var message = JsonConvert.SerializeObject(msgToSend, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new IsoDateTimeConverter() } }); - var clientSpecificMessage = msgToSend as MobileControlResponseMessage; - if (clientSpecificMessage != null) + var clientSpecificMessage = msgToSend as MobileControlMessage; + if (clientSpecificMessage.ClientId != null) { var clientId = clientSpecificMessage.ClientId; - Debug.Console(2, _server, "Message TX To Client ID: {0} Message: {1}", clientId, message); + Debug.Console(2, _server, "Message TX To Client ID: {0} Message: {1}", clientId, message); _server.SendMessageToClient(clientId, message); } - else + else { _server.SendMessageToAllClients(message); @@ -125,7 +125,7 @@ public void Dispatch() Debug.Console(1, "Cannot send. No server."); } } - catch(ThreadAbortException) + catch (ThreadAbortException) { //Swallowing this exception, as it occurs on shutdown and there's no need to print out a scary stack trace } @@ -134,7 +134,7 @@ public void Dispatch() Debug.Console(0, Debug.ErrorLogLevel.Error, "Caught an exception in the Transmit Processor {0}", ex.Message); Debug.Console(2, Debug.ErrorLogLevel.Error, "Stack Trace: {0}", ex.StackTrace); - if(ex.InnerException != null) + if (ex.InnerException != null) { Debug.Console(0, Debug.ErrorLogLevel.Error, "----\r\n{0}", ex.InnerException.Message); Debug.Console(2, Debug.ErrorLogLevel.Error, "Stack Trace: {0}", ex.InnerException.StackTrace); diff --git a/3-series/Volumes.cs b/3-series/Volumes.cs index d206906..8855667 100644 --- a/3-series/Volumes.cs +++ b/3-series/Volumes.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using Newtonsoft.Json; +using Newtonsoft.Json; +using System.Collections.Generic; namespace PepperDash.Essentials.Room.MobileControl { @@ -63,7 +63,7 @@ public Volume(string key, int level) } public Volume(string key, bool muted) - :this(key) + : this(key) { Muted = muted; } diff --git a/4-series/Directory.Build.targets b/4-series/Directory.Build.targets index 1b1c73d..807679e 100644 --- a/4-series/Directory.Build.targets +++ b/4-series/Directory.Build.targets @@ -25,14 +25,4 @@ - - - - doNotUse - - - doNotUse2 - - - diff --git a/4-series/epi-essentials-mobile-control/AuthorizationResponse.cs b/4-series/epi-essentials-mobile-control/AuthorizationResponse.cs new file mode 100644 index 0000000..4e4a443 --- /dev/null +++ b/4-series/epi-essentials-mobile-control/AuthorizationResponse.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +namespace PepperDash.Essentials +{ + public class AuthorizationResponse + { + [JsonProperty("authorized")] + public bool Authorized { get; set; } + + [JsonProperty("reason", NullValueHandling = NullValueHandling.Ignore)] + public string Reason { get; set; } = null; + } + + public class AuthorizationRequest + { + [JsonProperty("grantCode")] + public string GrantCode { get; set; } + } +} diff --git a/4-series/epi-essentials-mobile-control/MobileControlAction.cs b/4-series/epi-essentials-mobile-control/MobileControlAction.cs new file mode 100644 index 0000000..ac09fbc --- /dev/null +++ b/4-series/epi-essentials-mobile-control/MobileControlAction.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json.Linq; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Core.Web.RequestHandlers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PepperDash.Essentials +{ + public class MobileControlAction : IMobileControlAction + { + public IMobileControlMessenger Messenger { get; private set; } + + public Action Action {get; private set; } + + public MobileControlAction(IMobileControlMessenger messenger, Action handler) { + Messenger = messenger; + Action = handler; + } + } +} diff --git a/4-series/epi-essentials-mobile-control/Services/MobileControlApiService.cs b/4-series/epi-essentials-mobile-control/Services/MobileControlApiService.cs new file mode 100644 index 0000000..eeafcec --- /dev/null +++ b/4-series/epi-essentials-mobile-control/Services/MobileControlApiService.cs @@ -0,0 +1,67 @@ +using PepperDash.Core; +using System.Net.Http; +using System.Threading.Tasks; + +namespace PepperDash.Essentials.Services +{ + + public class MobileControlApiService + { + private readonly HttpClient _client; + + public MobileControlApiService(string apiUrl) + { + var handler = new HttpClientHandler + { + AllowAutoRedirect = false, + }; + + _client = new HttpClient(handler); + } + + public async Task SendAuthorizationRequest(string apiUrl, string grantCode, string systemUuid) + { + var request = new HttpRequestMessage(HttpMethod.Get, $"{apiUrl}/system/{systemUuid}/authorize?grantCode={grantCode}"); + + Debug.Console(1, $"Sending authorization request to {request.RequestUri}"); + + var response = await _client.SendAsync(request); + + var authResponse = new AuthorizationResponse + { + Authorized = response.StatusCode == System.Net.HttpStatusCode.OK + }; + + if (authResponse.Authorized) + { + return authResponse; + } + + if (response.StatusCode == System.Net.HttpStatusCode.Moved) + { + var location = response.Headers.Location; + + authResponse.Reason = $"ERROR: Mobile Control API has moved. Please adjust configuration to \"{location}\""; + + return authResponse; + } + + var responseString = await response.Content.ReadAsStringAsync(); + + switch (responseString) + { + case "codeNotFound": + authResponse.Reason = $"Authorization failed. Code not found for system UUID {systemUuid}"; + break; + case "uuidNotFound": + authResponse.Reason = $"Authorization failed. System UUID {systemUuid} not found. Check Essentials configuration."; + break; + default: + authResponse.Reason = $"Authorization failed. Response {response.StatusCode}: {responseString}"; + break; + } + + return authResponse; + } + } +} diff --git a/4-series/epi-essentials-mobile-control/Touchpanel/ITswAppControl.cs b/4-series/epi-essentials-mobile-control/Touchpanel/ITswAppControl.cs new file mode 100644 index 0000000..814b51c --- /dev/null +++ b/4-series/epi-essentials-mobile-control/Touchpanel/ITswAppControl.cs @@ -0,0 +1,25 @@ +using PepperDash.Core; +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.Touchpanel +{ + public interface ITswAppControl : IKeyed + { + BoolFeedback AppOpenFeedback { get; } + + void HideOpenApp(); + + void CloseOpenApp(); + + void OpenApp(); + } + + public interface ITswZoomControl : IKeyed + { + BoolFeedback ZoomIncomingCallFeedback { get; } + + BoolFeedback ZoomInCallFeedback { get; } + + void EndZoomCall(); + } +} diff --git a/4-series/epi-essentials-mobile-control/Touchpanel/ITswAppControlMessenger.cs b/4-series/epi-essentials-mobile-control/Touchpanel/ITswAppControlMessenger.cs new file mode 100644 index 0000000..52fa693 --- /dev/null +++ b/4-series/epi-essentials-mobile-control/Touchpanel/ITswAppControlMessenger.cs @@ -0,0 +1,59 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using PepperDash.Essentials.AppServer.Messengers; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; + +namespace PepperDash.Essentials.Touchpanel +{ + public class ITswAppControlMessenger : MessengerBase + { + private readonly ITswAppControl _appControl; + + public ITswAppControlMessenger(string key, string messagePath, Device device) : base(key, messagePath, device) + { + _appControl = device as ITswAppControl; + } + + protected override void RegisterActions() + { + if (_appControl == null) + { + Debug.Console(0, this, $"{_device.Key} does not implement ITswAppControl"); + return; + } + + AddAction($"/fullStatus", (id, context) => SendFullStatus()); + + AddAction($"/openApp", (id, context) => _appControl.OpenApp()); + + AddAction($"/closeApp", (id, context) => _appControl.CloseOpenApp()); + + AddAction($"/hideApp", (id, context) => _appControl.HideOpenApp()); + + _appControl.AppOpenFeedback.OutputChange += (s, a) => + { + PostStatusMessage(JToken.FromObject(new + { + appOpen = a.BoolValue + })); + }; + } + + private void SendFullStatus() + { + var message = new TswAppStateMessage + { + AppOpen = _appControl.AppOpenFeedback.BoolValue, + }; + + PostStatusMessage(message); + } + } + + public class TswAppStateMessage : DeviceStateMessageBase + { + [JsonProperty("appOpen", NullValueHandling = NullValueHandling.Ignore)] + public bool? AppOpen { get; set; } + } +} diff --git a/4-series/epi-essentials-mobile-control/Touchpanel/ITswZoomControlMessenger.cs b/4-series/epi-essentials-mobile-control/Touchpanel/ITswZoomControlMessenger.cs new file mode 100644 index 0000000..51ff355 --- /dev/null +++ b/4-series/epi-essentials-mobile-control/Touchpanel/ITswZoomControlMessenger.cs @@ -0,0 +1,71 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using PepperDash.Essentials.AppServer.Messengers; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; + + +namespace PepperDash.Essentials.Touchpanel +{ + public class ITswZoomControlMessenger : MessengerBase + { + private readonly ITswZoomControl _zoomControl; + + public ITswZoomControlMessenger(string key, string messagePath, Device device) : base(key, messagePath, device) + { + _zoomControl = device as ITswZoomControl; + } + + protected override void RegisterActions() + { + if (_zoomControl == null) + { + Debug.Console(0, this, $"{_device.Key} does not implement ITswZoomControl"); + return; + } + + AddAction($"/fullStatus", (id, context) => SendFullStatus()); + + + AddAction($"/endCall", (id, context) => _zoomControl.EndZoomCall()); + + _zoomControl.ZoomIncomingCallFeedback.OutputChange += (s, a) => + { + PostStatusMessage(JToken.FromObject(new + { + incomingCall = a.BoolValue, + })); + }; + + + _zoomControl.ZoomInCallFeedback.OutputChange += (s, a) => + { + PostStatusMessage(JToken.FromObject( + new + { + inCall = a.BoolValue, + })); + }; + } + + private void SendFullStatus() + { + var message = new TswZoomStateMessage + { + InCall = _zoomControl?.ZoomInCallFeedback.BoolValue, + IncomingCall = _zoomControl?.ZoomIncomingCallFeedback.BoolValue + }; + + PostStatusMessage(message); + } + } + + public class TswZoomStateMessage : DeviceStateMessageBase + { + [JsonProperty("inCall", NullValueHandling = NullValueHandling.Ignore)] + public bool? InCall { get; set; } + + [JsonProperty("incomingCall", NullValueHandling = NullValueHandling.Ignore)] + public bool? IncomingCall { get; set; } + } +} diff --git a/4-series/epi-essentials-mobile-control/Touchpanel/MobileControlTouchpanelController.cs b/4-series/epi-essentials-mobile-control/Touchpanel/MobileControlTouchpanelController.cs new file mode 100644 index 0000000..705269f --- /dev/null +++ b/4-series/epi-essentials-mobile-control/Touchpanel/MobileControlTouchpanelController.cs @@ -0,0 +1,513 @@ +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.UI; +using Newtonsoft.Json; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Core.DeviceInfo; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Core.UI; +using PepperDash.Essentials.Touchpanel; +using System; +using System.Collections.Generic; +using System.Linq; +using Feedback = PepperDash.Essentials.Core.Feedback; + +namespace PepperDash.Essentials.Devices.Common.TouchPanel +{ + //public interface IMobileControlTouchpanelController + //{ + // StringFeedback AppUrlFeedback { get; } + // string DefaultRoomKey { get; } + // string DeviceKey { get; } + //} + + + public class MobileControlTouchpanelController : TouchpanelBase, IHasFeedback, ITswAppControl, ITswZoomControl, IDeviceInfoProvider, IMobileControlTouchpanelController + { + private readonly MobileControlTouchpanelProperties localConfig; + private IMobileControlRoomMessenger _bridge; + + private string _appUrl; + + public StringFeedback AppUrlFeedback { get; private set; } + private readonly StringFeedback QrCodeUrlFeedback; + private readonly StringFeedback McServerUrlFeedback; + private readonly StringFeedback UserCodeFeedback; + + private readonly BoolFeedback _appOpenFeedback; + + public BoolFeedback AppOpenFeedback => _appOpenFeedback; + + private readonly BoolFeedback _zoomIncomingCallFeedback; + + public BoolFeedback ZoomIncomingCallFeedback => _zoomIncomingCallFeedback; + + private readonly BoolFeedback _zoomInCallFeedback; + + public event DeviceInfoChangeHandler DeviceInfoChanged; + + public BoolFeedback ZoomInCallFeedback => _zoomInCallFeedback; + + + public FeedbackCollection Feedbacks { get; private set; } + + public FeedbackCollection ZoomFeedbacks { get; private set; } + + public string DefaultRoomKey => _config.DefaultRoomKey; + + public bool UseDirectServer => localConfig.UseDirectServer; + + public bool ZoomRoomController => localConfig.ZoomRoomController; + + public DeviceInfo DeviceInfo => new DeviceInfo(); + + public MobileControlTouchpanelController(string key, string name, BasicTriListWithSmartObject panel, MobileControlTouchpanelProperties config) : base(key, name, panel, config) + { + localConfig = config; + + AddPostActivationAction(SubscribeForMobileControlUpdates); + + AppUrlFeedback = new StringFeedback(() => _appUrl); + QrCodeUrlFeedback = new StringFeedback(() => _bridge?.QrCodeUrl); + McServerUrlFeedback = new StringFeedback(() => _bridge?.McServerUrl); + UserCodeFeedback = new StringFeedback(() => _bridge?.UserCode); + + _appOpenFeedback = new BoolFeedback($"{Key}-appOpen", () => + { + if (Panel is TswX60BaseClass tsX60) + { + Debug.Console(2, this, $"x60 sending {tsX60.ExtenderApplicationControlReservedSigs.HideOpenApplicationFeedback.BoolValue}"); + return !tsX60.ExtenderApplicationControlReservedSigs.HideOpenApplicationFeedback.BoolValue; + } + + if (Panel is TswX70Base tsX70) + { + Debug.Console(2, this, $"x70 sending {tsX70.ExtenderApplicationControlReservedSigs.HideOpenedApplicationFeedback.BoolValue}"); + return !tsX70.ExtenderApplicationControlReservedSigs.HideOpenedApplicationFeedback.BoolValue; + } + + return false; + }); + + _zoomIncomingCallFeedback = new BoolFeedback($"{Key}-zoomIncomingCall", () => + { + if (Panel is TswX60WithZoomRoomAppReservedSigs tsX60) + { + return tsX60.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.BoolValue; + } + + if (Panel is TswX70Base tsX70) + { + return tsX70.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.BoolValue; + } + + return false; + }); + + _zoomInCallFeedback = new BoolFeedback($"{Key}-zoomInCall", () => + { + if (Panel is TswX60WithZoomRoomAppReservedSigs tsX60) + { + return tsX60.ExtenderZoomRoomAppReservedSigs.ZoomRoomActiveFeedback.BoolValue; + } + + if (Panel is TswX70Base tsX70) + { + return tsX70.ExtenderZoomRoomAppReservedSigs.ZoomRoomActiveFeedback.BoolValue; + } + + return false; + }); + + Feedbacks = new FeedbackCollection + { + AppUrlFeedback, QrCodeUrlFeedback, McServerUrlFeedback, UserCodeFeedback + }; + + ZoomFeedbacks = new FeedbackCollection { + AppOpenFeedback, _zoomInCallFeedback, _zoomIncomingCallFeedback + }; + + RegisterForExtenders(); + } + + private void RegisterForExtenders() + { + if (Panel is TswXX70Base x70Panel) + { + x70Panel.ExtenderApplicationControlReservedSigs.DeviceExtenderSigChange += (e, a) => + { + Debug.Console(2, this, $"X70 App Control Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}"); + UpdateZoomFeedbacks(); + + if (!x70Panel.ExtenderApplicationControlReservedSigs.HideOpenedApplicationFeedback.BoolValue) + { + x70Panel.ExtenderButtonToolbarReservedSigs.ShowButtonToolbar(); + x70Panel.ExtenderButtonToolbarReservedSigs.Button2On(); + } else + { + x70Panel.ExtenderButtonToolbarReservedSigs.HideButtonToolbar(); + x70Panel.ExtenderButtonToolbarReservedSigs.Button2Off(); + } + }; + + + x70Panel.ExtenderZoomRoomAppReservedSigs.DeviceExtenderSigChange += (e, a) => + { + Debug.Console(2, this, $"X70 Zoom Room Ap Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}"); + UpdateZoomFeedbacks(); + }; + + + x70Panel.ExtenderEthernetReservedSigs.DeviceExtenderSigChange += (e, a) => + { + DeviceInfo.MacAddress = x70Panel.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; + DeviceInfo.IpAddress = x70Panel.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; + + Debug.Console(1, this, $"MAC: {DeviceInfo.MacAddress} IP: {DeviceInfo.IpAddress}"); + + var handler = DeviceInfoChanged; + + if(handler == null) + { + return; + } + + handler(this, new DeviceInfoEventArgs(DeviceInfo)); + }; + + x70Panel.ExtenderApplicationControlReservedSigs.Use(); + x70Panel.ExtenderZoomRoomAppReservedSigs.Use(); + x70Panel.ExtenderEthernetReservedSigs.Use(); + x70Panel.ExtenderButtonToolbarReservedSigs.Use(); + + x70Panel.ExtenderButtonToolbarReservedSigs.Button1Off(); + x70Panel.ExtenderButtonToolbarReservedSigs.Button3Off(); + x70Panel.ExtenderButtonToolbarReservedSigs.Button4Off(); + x70Panel.ExtenderButtonToolbarReservedSigs.Button5Off(); + x70Panel.ExtenderButtonToolbarReservedSigs.Button6Off(); + + return; + } + + if (Panel is TswX60WithZoomRoomAppReservedSigs x60withZoomApp) + { + x60withZoomApp.ExtenderApplicationControlReservedSigs.DeviceExtenderSigChange += (e, a) => + { + Debug.Console(2, this, $"X60 App Control Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}"); + UpdateZoomFeedbacks(); + }; + x60withZoomApp.ExtenderZoomRoomAppReservedSigs.DeviceExtenderSigChange += (e, a) => + { + Debug.Console(2, this, $"X60 Zoom Room App Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}"); + UpdateZoomFeedbacks(); + }; + + x60withZoomApp.ExtenderEthernetReservedSigs.DeviceExtenderSigChange += (e, a) => + { + DeviceInfo.MacAddress = x60withZoomApp.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; + DeviceInfo.IpAddress = x60withZoomApp.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; + + Debug.Console(1, this, $"MAC: {DeviceInfo.MacAddress} IP: {DeviceInfo.IpAddress}"); + + var handler = DeviceInfoChanged; + + if (handler == null) + { + return; + } + + handler(this, new DeviceInfoEventArgs(DeviceInfo)); + }; + + x60withZoomApp.ExtenderZoomRoomAppReservedSigs.Use(); + x60withZoomApp.ExtenderApplicationControlReservedSigs.Use(); + x60withZoomApp.ExtenderEthernetReservedSigs.Use(); + } + } + + public override bool CustomActivate() + { + if (!(Panel is TswXX70Base) && !(Panel is TswX60WithZoomRoomAppReservedSigs)) + { + return base.CustomActivate(); + } + var appMessenger = new ITswAppControlMessenger($"appControlMessenger-{Key}", $"/device/{Key}", this); + + var zoomMessenger = new ITswZoomControlMessenger($"zoomControlMessenger-{Key}", $"/device/{Key}", this); + + var mc = DeviceManager.AllDevices.OfType().FirstOrDefault(); + + if (mc == null) + { + return base.CustomActivate(); + } + + mc.AddDeviceMessenger(appMessenger); + mc.AddDeviceMessenger(zoomMessenger); + + return base.CustomActivate(); + } + + + protected override void ExtenderSystemReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args) + { + Debug.Console(2, this, $"System Device Extender args: ${args.Event}:${args.Sig}"); + } + + protected override void SetupPanelDrivers(string roomKey) + { + AppUrlFeedback.LinkInputSig(Panel.StringInput[1]); + QrCodeUrlFeedback.LinkInputSig(Panel.StringInput[2]); + McServerUrlFeedback.LinkInputSig(Panel.StringInput[3]); + UserCodeFeedback.LinkInputSig(Panel.StringInput[4]); + + Panel.OnlineStatusChange += (sender, args) => + { + UpdateFeedbacks(); + + Panel.StringInput[1].StringValue = AppUrlFeedback.StringValue; + Panel.StringInput[2].StringValue = QrCodeUrlFeedback.StringValue; + Panel.StringInput[3].StringValue = McServerUrlFeedback.StringValue; + Panel.StringInput[4].StringValue = UserCodeFeedback.StringValue; + }; + } + + private void SubscribeForMobileControlUpdates() + { + foreach (var dev in DeviceManager.AllDevices) + { + Debug.Console(0, this, $"{dev.Key}:{dev.GetType().Name}"); + } + + var mcList = DeviceManager.AllDevices.OfType().ToList(); + + if (mcList.Count == 0) + { + Debug.Console(0, this, $"No Mobile Control controller found"); + + return; + } + + // use first in list, since there should only be one. + var mc = mcList[0]; + + var bridge = mc.GetRoomBridge(_config.DefaultRoomKey); + + if (bridge == null) + { + Debug.Console(0, this, $"No Mobile Control bridge for {_config.DefaultRoomKey} found "); + return; + } + + _bridge = bridge; + + _bridge.UserCodeChanged += UpdateFeedbacks; + _bridge.AppUrlChanged += (s, a) => { Debug.Console(0, this, "AppURL changed"); UpdateFeedbacks(s, a); }; + } + + public void SetAppUrl(string url) + { + _appUrl = url; + AppUrlFeedback.FireUpdate(); + } + + private void UpdateFeedbacks(object sender, EventArgs args) + { + UpdateFeedbacks(); + } + + private void UpdateFeedbacks() + { + foreach (var feedback in Feedbacks) { feedback.FireUpdate(); } + } + + private void UpdateZoomFeedbacks() + { + foreach (var feedback in ZoomFeedbacks) + { + Debug.Console(1, this, $"Updating {feedback.Key}"); + feedback.FireUpdate(); + } + } + + public void HideOpenApp() + { + if (Panel is TswX70Base x70Panel) + { + x70Panel.ExtenderApplicationControlReservedSigs.HideOpenedApplication(); + return; + } + + if (Panel is TswX60BaseClass x60Panel) + { + x60Panel.ExtenderApplicationControlReservedSigs.HideOpenApplication(); + return; + } + } + + public void OpenApp() + { + if (Panel is TswX70Base x70Panel) + { + x70Panel.ExtenderApplicationControlReservedSigs.OpenApplication(); + return; + } + + if (Panel is TswX60WithZoomRoomAppReservedSigs) + { + Debug.Console(0, this, $"X60 panel does not support zoom app"); + return; + } + } + + public void CloseOpenApp() + { + if (Panel is TswX70Base x70Panel) + { + x70Panel.ExtenderApplicationControlReservedSigs.CloseOpenedApplication(); + return; + } + + if (Panel is TswX60WithZoomRoomAppReservedSigs x60Panel) + { + x60Panel.ExtenderApplicationControlReservedSigs.CloseOpenedApplication(); + return; + } + } + + public void EndZoomCall() + { + if (Panel is TswX70Base x70Panel) + { + x70Panel.ExtenderZoomRoomAppReservedSigs.ZoomRoomEndCall(); + return; + } + + if (Panel is TswX60WithZoomRoomAppReservedSigs x60Panel) + { + x60Panel.ExtenderZoomRoomAppReservedSigs.ZoomRoomEndCall(); + return; + } + } + + public void UpdateDeviceInfo() + { + if (Panel is TswXX70Base x70Panel) + { + DeviceInfo.MacAddress = x70Panel.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; + DeviceInfo.IpAddress = x70Panel.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; + + var handler = DeviceInfoChanged; + + if (handler == null) + { + return; + } + + handler(this, new DeviceInfoEventArgs(DeviceInfo)); + } + + if (Panel is TswX60WithZoomRoomAppReservedSigs x60Panel) + { + DeviceInfo.MacAddress = x60Panel.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; + DeviceInfo.IpAddress = x60Panel.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; + + var handler = DeviceInfoChanged; + + if (handler == null) + { + return; + } + + handler(this, new DeviceInfoEventArgs(DeviceInfo)); + } + + Debug.Console(1, this, $"MAC: {DeviceInfo.MacAddress} IP: {DeviceInfo.IpAddress}"); + } + } + + public class MobileControlTouchpanelControllerFactory : EssentialsPluginDeviceFactory + { + public MobileControlTouchpanelControllerFactory() + { + TypeNames = new List() { "mccrestronapp", "mctsw550", "mctsw750", "mctsw1050", "mctsw560", "mctsw760", "mctsw1060", "mctsw570", "mctsw770", "mcts770", "mctsw1070", "mcts1070", "mcxpanel" }; + MinimumEssentialsFrameworkVersion = "2.0.0"; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + var comm = CommFactory.GetControlPropertiesConfig(dc); + var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); + + var panel = GetPanelForType(dc.Type, comm.IpIdInt, props.ProjectName); + + if (panel == null) + { + Debug.Console(0, "Unable to create Touchpanel for type {0}. Touchpanel Controller WILL NOT function correctly", dc.Type); + } + + Debug.Console(1, "Factory Attempting to create new MobileControlTouchpanelController"); + + var panelController = new MobileControlTouchpanelController(dc.Key, dc.Name, panel, props); + + return panelController; + } + + private BasicTriListWithSmartObject GetPanelForType(string type, uint id, string projectName) + { + type = type.ToLower().Replace("mc", ""); + try + { + if (type == "crestronapp") + { + var app = new CrestronApp(id, Global.ControlSystem); + app.ParameterProjectName.Value = projectName; + return app; + } + else if (type == "xpanel") + return new XpanelForHtml5(id, Global.ControlSystem); + else if (type == "tsw550") + return new Tsw550(id, Global.ControlSystem); + else if (type == "tsw552") + return new Tsw552(id, Global.ControlSystem); + else if (type == "tsw560") + return new Tsw560(id, Global.ControlSystem); + else if (type == "tsw750") + return new Tsw750(id, Global.ControlSystem); + else if (type == "tsw752") + return new Tsw752(id, Global.ControlSystem); + else if (type == "tsw760") + return new Tsw760(id, Global.ControlSystem); + else if (type == "tsw1050") + return new Tsw1050(id, Global.ControlSystem); + else if (type == "tsw1052") + return new Tsw1052(id, Global.ControlSystem); + else if (type == "tsw1060") + return new Tsw1060(id, Global.ControlSystem); + else if (type == "tsw570") + return new Tsw570(id, Global.ControlSystem); + else if (type == "tsw770") + return new Tsw770(id, Global.ControlSystem); + else if (type == "ts770") + return new Ts770(id, Global.ControlSystem); + else if (type == "tsw1070") + return new Tsw1070(id, Global.ControlSystem); + else if (type == "ts1070") + return new Ts1070(id, Global.ControlSystem); + else + { + Debug.Console(0, Debug.ErrorLogLevel.Notice, "WARNING: Cannot create TSW controller with type '{0}'", type); + return null; + } + } + catch (Exception e) + { + Debug.Console(0, Debug.ErrorLogLevel.Notice, "WARNING: Cannot create TSW base class. Panel will not function: {0}", e.Message); + return null; + } + } + } +} diff --git a/4-series/epi-essentials-mobile-control/Touchpanel/MobileControlTouchpanelProperties.cs b/4-series/epi-essentials-mobile-control/Touchpanel/MobileControlTouchpanelProperties.cs new file mode 100644 index 0000000..a72eaa6 --- /dev/null +++ b/4-series/epi-essentials-mobile-control/Touchpanel/MobileControlTouchpanelProperties.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.Devices.Common.TouchPanel +{ + public class MobileControlTouchpanelProperties : CrestronTouchpanelPropertiesConfig + { + [JsonProperty("useDirectServer")] + public bool UseDirectServer { get; set; } = false; + + [JsonProperty("zoomRoomController")] + public bool ZoomRoomController { get; set; } = false; + + [JsonProperty("buttonToolbarTimeoutInS")] + public ushort ButtonToolbarTimoutInS { get; set; } = 0; + } +} \ No newline at end of file diff --git a/4-series/epi-essentials-mobile-control/UserCodeChangedContent.cs b/4-series/epi-essentials-mobile-control/UserCodeChangedContent.cs new file mode 100644 index 0000000..ef00442 --- /dev/null +++ b/4-series/epi-essentials-mobile-control/UserCodeChangedContent.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace PepperDash.Essentials.AppServer +{ + public class UserCodeChangedContent + { + [JsonProperty("userCode")] + public string UserCode { get; set; } + + [JsonProperty("qrChecksum", NullValueHandling = NullValueHandling.Include)] + public string QrChecksum { get; set; } + } +} diff --git a/4-series/epi-essentials-mobile-control/WebApiHandlers/ActionPathsHandler.cs b/4-series/epi-essentials-mobile-control/WebApiHandlers/ActionPathsHandler.cs new file mode 100644 index 0000000..7351cc1 --- /dev/null +++ b/4-series/epi-essentials-mobile-control/WebApiHandlers/ActionPathsHandler.cs @@ -0,0 +1,52 @@ +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; +using PepperDash.Core.Web.RequestHandlers; +using PepperDash.Essentials.AppServer.Messengers; +using System.Collections.Generic; +using System.Linq; + +namespace PepperDash.Essentials.WebApiHandlers +{ + public class ActionPathsHandler : WebApiBaseRequestHandler + { + private readonly MobileControlSystemController mcController; + public ActionPathsHandler(MobileControlSystemController controller) : base(true) + { + mcController = controller; + } + + protected override void HandleGet(HttpCwsContext context) + { + var response = JsonConvert.SerializeObject(new ActionPathsResponse(mcController)); + + context.Response.StatusCode = 200; + context.Response.ContentType = "application/json"; + context.Response.Headers.Add("Content-Type", "application/json"); + context.Response.Write(response, false); + context.Response.End(); + } + } + + public class ActionPathsResponse + { + [JsonIgnore] + private readonly MobileControlSystemController mcController; + + [JsonProperty("actionPaths")] + public List ActionPaths => mcController.GetActionDictionaryPaths().Select((path) => new ActionPath { MessengerKey = path.Item1, Path = path.Item2}).ToList(); + + public ActionPathsResponse(MobileControlSystemController mcController) + { + this.mcController = mcController; + } + } + + public class ActionPath + { + [JsonProperty("messengerKey")] + public string MessengerKey { get; set; } + + [JsonProperty("path")] + public string Path { get; set; } + } +} diff --git a/4-series/epi-essentials-mobile-control/WebApiHandlers/MobileAuthRequestHandler.cs b/4-series/epi-essentials-mobile-control/WebApiHandlers/MobileAuthRequestHandler.cs new file mode 100644 index 0000000..2dc8407 --- /dev/null +++ b/4-series/epi-essentials-mobile-control/WebApiHandlers/MobileAuthRequestHandler.cs @@ -0,0 +1,64 @@ +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; +using PepperDash.Core; +using PepperDash.Core.Web.RequestHandlers; +using PepperDash.Essentials.Core.Web; +using System; +using System.Threading.Tasks; + +namespace PepperDash.Essentials.WebApiHandlers +{ + public class MobileAuthRequestHandler : WebApiBaseRequestAsyncHandler + { + private readonly MobileControlSystemController mcController; + + public MobileAuthRequestHandler(MobileControlSystemController controller) : base(true) + { + mcController = controller; + } + + protected override async Task HandlePost(HttpCwsContext context) + { + var requestBody = EssentialsWebApiHelpers.GetRequestBody(context.Request); + + var grantCode = JsonConvert.DeserializeObject(requestBody); + + if (string.IsNullOrEmpty(grantCode?.GrantCode)) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Missing grant code"; + context.Response.End(); + return; + } + + var response = await mcController.ApiService.SendAuthorizationRequest(mcController.Host, grantCode.GrantCode, mcController.SystemUuid); + + Debug.Console(1, $"response received"); + if (response.Authorized) + { + mcController.RegisterSystemToServer(); + } + + try + { + context.Response.StatusCode = 200; + var responseBody = JsonConvert.SerializeObject(response, Formatting.None); + context.Response.ContentType = "application/json"; + context.Response.Headers.Add("Content-Type", "application/json"); + context.Response.Write(responseBody, false); + context.Response.End(); + } + catch (Exception ex) + { + Debug.Console(0, $"Exception handling MC Auth request: {ex.Message}"); + Debug.Console(2, $"Stack Trace: {ex.StackTrace}"); + + if (ex.InnerException != null) + { + Debug.Console(0, $"Inner Exception: {ex.InnerException.Message}"); + Debug.Console(2, $"Inner Exception Stack Trace: {ex.InnerException.StackTrace}"); + } + } + } + } +} diff --git a/4-series/epi-essentials-mobile-control/WebApiHandlers/MobileInfoHandler.cs b/4-series/epi-essentials-mobile-control/WebApiHandlers/MobileInfoHandler.cs new file mode 100644 index 0000000..f0c1809 --- /dev/null +++ b/4-series/epi-essentials-mobile-control/WebApiHandlers/MobileInfoHandler.cs @@ -0,0 +1,159 @@ +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; +using PepperDash.Core; +using PepperDash.Core.Web.RequestHandlers; +using PepperDash.Essentials.Core.Config; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace PepperDash.Essentials.WebApiHandlers +{ + public class MobileInfoHandler : WebApiBaseRequestHandler + { + private readonly MobileControlSystemController mcController; + public MobileInfoHandler(MobileControlSystemController controller) : base(true) + { + mcController = controller; + } + + protected override void HandleGet(HttpCwsContext context) + { + try + { + var response = new InformationResponse(mcController); + + context.Response.StatusCode = 200; + context.Response.ContentType = "application/json"; + context.Response.Write(JsonConvert.SerializeObject(response), false); + context.Response.End(); + } + catch (Exception ex) + { + Debug.Console(1, $"exception showing mobile info: {ex.Message}"); + Debug.Console(2, $"stack trace: {ex.StackTrace}"); + + context.Response.StatusCode = 500; + context.Response.End(); + } + } + } + + public class InformationResponse + { + [JsonIgnore] + private readonly MobileControlSystemController mcController; + + [JsonProperty("edgeServer", NullValueHandling = NullValueHandling.Ignore)] + public MobileControlEdgeServer EdgeServer => mcController.Config.EnableApiServer ? new MobileControlEdgeServer(mcController) : null; + + + [JsonProperty("directServer", NullValueHandling = NullValueHandling.Ignore)] + public MobileControlDirectServer DirectServer => mcController.Config.DirectServer.EnableDirectServer ? new MobileControlDirectServer(mcController.DirectServer) : null; + + + public InformationResponse(MobileControlSystemController controller) + { + mcController = controller; + } + } + + public class MobileControlEdgeServer + { + [JsonIgnore] + private readonly MobileControlSystemController mcController; + + [JsonProperty("serverAddress")] + public string ServerAddress => mcController.Config == null ? "No Config" : mcController.Host; + + [JsonProperty("systemName")] + public string SystemName => mcController.RoomBridges.Count > 0 ? mcController.RoomBridges[0].RoomName : "No Config"; + + [JsonProperty("systemUrl")] + public string SystemUrl => ConfigReader.ConfigObject.SystemUrl; + + [JsonProperty("userCode")] + public string UserCode => mcController.RoomBridges.Count > 0 ? mcController.RoomBridges[0].UserCode : "Not available"; + + [JsonProperty("connected")] + public bool Connected => mcController.Connected; + + [JsonProperty("secondsSinceLastAck")] + public int SecondsSinceLastAck => (DateTime.Now - mcController.LastAckMessage).Seconds; + + public MobileControlEdgeServer(MobileControlSystemController controller) + { + mcController = controller; + } + } + + public class MobileControlDirectServer + { + [JsonIgnore] + private readonly MobileControlWebsocketServer directServer; + + [JsonProperty("userAppUrl")] + public string UserAppUrl => $"{directServer.UserAppUrlPrefix}/[insert_client_token]"; + + [JsonProperty("serverPort")] + public int ServerPort => directServer.Port; + + [JsonProperty("tokensDefined")] + public int TokensDefined => directServer.UiClients.Count; + + [JsonProperty("clientsConnected")] + public int ClientsConnected => directServer.ConnectedUiClientsCount; + + [JsonProperty("clients")] + public List Clients => directServer.UiClients.Select((c, i) => { return new MobileControlDirectClient(c, i, directServer.UserAppUrlPrefix); }).ToList(); + + public MobileControlDirectServer(MobileControlWebsocketServer server) + { + directServer = server; + } + } + + public class MobileControlDirectClient + { + [JsonIgnore] + private readonly UiClientContext context; + + [JsonIgnore] + private readonly string Key; + + [JsonIgnore] + private readonly int clientNumber; + + [JsonIgnore] + private readonly string urlPrefix; + + [JsonProperty("clientNumber")] + public string ClientNumber => $"{clientNumber}"; + + [JsonProperty("roomKey")] + public string RoomKey => context.Token.RoomKey; + + [JsonProperty("touchpanelKey")] + public string TouchpanelKey => context.Token.TouchpanelKey; + + [JsonProperty("url")] + public string Url => $"{urlPrefix}{Key}"; + + [JsonProperty("token")] + public string Token => Key; + + [JsonProperty("connected")] + public bool Connected => context.Client == null ? false : context.Client.Context.WebSocket.IsAlive; + + [JsonProperty("duration")] + public double Duration => context.Client == null ? 0 : context.Client.ConnectedDuration.TotalSeconds; + + public MobileControlDirectClient(KeyValuePair clientContext, int index, string urlPrefix) + { + context = clientContext.Value; + Key = clientContext.Key; + clientNumber = index; + this.urlPrefix = urlPrefix; + } + } +} diff --git a/4-series/epi-essentials-mobile-control/WebApiHandlers/UiClientHandler.cs b/4-series/epi-essentials-mobile-control/WebApiHandlers/UiClientHandler.cs new file mode 100644 index 0000000..537dafb --- /dev/null +++ b/4-series/epi-essentials-mobile-control/WebApiHandlers/UiClientHandler.cs @@ -0,0 +1,164 @@ +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; +using PepperDash.Core; +using PepperDash.Core.Web.RequestHandlers; +using PepperDash.Essentials.Core.Web; + +namespace PepperDash.Essentials.WebApiHandlers +{ + public class UiClientHandler : WebApiBaseRequestHandler + { + private readonly MobileControlWebsocketServer server; + public UiClientHandler(MobileControlWebsocketServer directServer) : base(true) + { + server = directServer; + } + + protected override void HandlePost(HttpCwsContext context) + { + var req = context.Request; + var res = context.Response; + var body = EssentialsWebApiHelpers.GetRequestBody(req); + + var request = JsonConvert.DeserializeObject(body); + + var response = new ClientResponse(); + + if (string.IsNullOrEmpty(request?.RoomKey)) + { + response.Error = "roomKey is required"; + + res.StatusCode = 400; + res.ContentType = "application/json"; + res.Headers.Add("Content-Type", "application/json"); + res.Write(JsonConvert.SerializeObject(response), false); + res.End(); + return; + } + + if (string.IsNullOrEmpty(request.GrantCode)) + { + response.Error = "grantCode is required"; + + res.StatusCode = 400; + res.ContentType = "application/json"; + res.Headers.Add("Content-Type", "application/json"); + res.Write(JsonConvert.SerializeObject(response), false); + res.End(); + return; + } + + var (token, path) = server.ValidateGrantCode(request.GrantCode, request.RoomKey); + + response.Token = token; + response.Path = path; + + res.StatusCode = 200; + res.ContentType = "application/json"; + res.Headers.Add("Content-Type", "application/json"); + res.Write(JsonConvert.SerializeObject(response), false); + res.End(); + } + + protected override void HandleDelete(HttpCwsContext context) + { + var req = context.Request; + var res = context.Response; + var body = EssentialsWebApiHelpers.GetRequestBody(req); + + var request = JsonConvert.DeserializeObject(body); + + + + if (string.IsNullOrEmpty(request?.Token)) + { + var response = new ClientResponse + { + Error = "token is required" + }; + + res.StatusCode = 400; + res.ContentType = "application/json"; + res.Headers.Add("Content-Type", "application/json"); + res.Write(JsonConvert.SerializeObject(response), false); + res.End(); + + return; + } + + + + if (!server.UiClients.TryGetValue(request.Token, out UiClientContext clientContext)) + { + var response = new ClientResponse + { + Error = $"Unable to find client with token: {request.Token}" + }; + + res.StatusCode = 200; + res.ContentType = "application/json"; + res.Headers.Add("Content-Type", "application/json"); + res.Write(JsonConvert.SerializeObject(response), false); + res.End(); + + return; + } + + if (clientContext.Client != null && clientContext.Client.Context.WebSocket.IsAlive) + { + clientContext.Client.Context.WebSocket.Close(WebSocketSharp.CloseStatusCode.Normal, "Token removed from server"); + } + + var path = server.WsPath + request.Token; + + if (!server.Server.RemoveWebSocketService(path)) + { + Debug.Console(0, $"Unable to remove client with token {request.Token}"); + + var response = new ClientResponse + { + Error = $"Unable to remove client with token {request.Token}" + }; + + res.StatusCode = 500; + res.ContentType = "application/json"; + res.Headers.Add("Content-Type", "application/json"); + res.Write(JsonConvert.SerializeObject(response), false); + res.End(); + + return; + } + + server.UiClients.Remove(request.Token); + + server.UpdateSecret(); + + res.StatusCode = 200; + res.End(); + } + } + + public class ClientRequest + { + [JsonProperty("roomKey", NullValueHandling = NullValueHandling.Ignore)] + public string RoomKey { get; set; } + + [JsonProperty("grantCode", NullValueHandling = NullValueHandling.Ignore)] + public string GrantCode { get; set; } + + [JsonProperty("token", NullValueHandling = NullValueHandling.Ignore)] + public string Token { get; set; } + } + + public class ClientResponse + { + [JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)] + public string Error { get; set; } + + [JsonProperty("token", NullValueHandling = NullValueHandling.Ignore)] + public string Token { get; set; } + + [JsonProperty("path", NullValueHandling = NullValueHandling.Ignore)] + public string Path { get; set; } + } +} diff --git a/4-series/epi-essentials-mobile-control/WebSocketServer/MobileControlWebsocketServer.cs b/4-series/epi-essentials-mobile-control/WebSocketServer/MobileControlWebsocketServer.cs index e2fb028..b167fd6 100644 --- a/4-series/epi-essentials-mobile-control/WebSocketServer/MobileControlWebsocketServer.cs +++ b/4-series/epi-essentials-mobile-control/WebSocketServer/MobileControlWebsocketServer.cs @@ -1,16 +1,26 @@ using Crestron.SimplSharp; -using Crestron.SimplSharp.CrestronIO; +using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using PepperDash.Core; +using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Core.Web; +using PepperDash.Essentials.Devices.Common.TouchPanel; +using PepperDash.Essentials.WebApiHandlers; using System; using System.Collections.Generic; +using System.IO; +using System.Linq; using System.Net.Http; using System.Text; using System.Text.RegularExpressions; using WebSocketSharp; using WebSocketSharp.Net; using WebSocketSharp.Server; +using ErrorEventArgs = WebSocketSharp.ErrorEventArgs; + namespace PepperDash.Essentials { @@ -18,7 +28,7 @@ namespace PepperDash.Essentials /// Represents the behaviour to associate with a UiClient for WebSocket communication /// public class UiClient : WebSocketBehavior - { + { public MobileControlSystemController Controller { get; set; } public string RoomKey { get; set; } @@ -42,8 +52,8 @@ public TimeSpan ConnectedDuration public UiClient() { - - } + + } protected override void OnOpen() { @@ -56,12 +66,12 @@ protected override void OnOpen() if (match.Success) { - var clientId = match.Groups[1].Value; - + var clientId = match.Groups[1].Value; + // Inform controller of client joining if (Controller != null) { - var clientJoined = new MobileControlResponseMessage + var clientJoined = new MobileControlMessage { Type = "/system/roomKey", ClientId = clientId, @@ -88,18 +98,18 @@ protected override void OnOpen() } private void SendUserCodeToClient(MobileControlBridgeBase bridge, string clientId) - { + { var content = new { userCode = bridge.UserCode, qrUrl = bridge.QrCodeUrl, }; - var message = new MobileControlResponseMessage + var message = new MobileControlMessage { - Type = "/system/userCodeChanged", + Type = "/system/userCodeChanged", ClientId = clientId, - Content = content + Content = JToken.FromObject(content) }; Controller.SendMessageObjectToDirectClient(message); @@ -134,11 +144,11 @@ protected override void OnError(ErrorEventArgs e) public class MobileControlWebsocketServer : EssentialsDevice { - private string userAppPath = Global.FilePathPrefix + "mcUserApp" + Global.DirectorySeparator; + private readonly string userAppPath = Global.FilePathPrefix + "mcUserApp" + Global.DirectorySeparator; - private string localConfigFolderName = "_local-config"; + private readonly string localConfigFolderName = "_local-config"; - private string appConfigFileName = "_config.local.json"; + private readonly string appConfigFileName = "_config.local.json"; /// /// Where the key is the join token and the value is the room key @@ -147,17 +157,19 @@ public class MobileControlWebsocketServer : EssentialsDevice private HttpServer _server; + public HttpServer Server => _server; + public Dictionary UiClients { get; private set; } - private MobileControlSystemController _parent; + private readonly MobileControlSystemController _parent; private WebSocketServerSecretProvider _secretProvider; private ServerTokenSecrets _secret; - private static HttpClient LogClient = new HttpClient(); + private static readonly HttpClient LogClient = new HttpClient(); - private string _secretProviderKey + private string SecretProviderKey { get { @@ -168,12 +180,14 @@ private string _secretProviderKey /// /// The path for the WebSocket messaging /// - private string _wsPath = "/mc/api/ui/join/"; + private readonly string _wsPath = "/mc/api/ui/join/"; + + public string WsPath => _wsPath; /// /// The path to the location of the files for the user app (single page Angular app) /// - private string _appPath = string.Format("{0}mcUserApp", Global.FilePathPrefix); + private readonly string _appPath = string.Format("{0}mcUserApp", Global.FilePathPrefix); /// /// The base HREF that the user app uses @@ -185,7 +199,7 @@ private string _secretProviderKey /// public int Port { get; private set; } - public string UserAppUrlPrefix + public string UserAppUrlPrefix { get { @@ -214,7 +228,7 @@ public int ConnectedUiClientsCount return count; } } - + public MobileControlWebsocketServer(string key, int customPort, MobileControlSystemController parent) : base(key) { @@ -232,7 +246,39 @@ public MobileControlWebsocketServer(string key, int customPort, MobileControlSys //_joinTokens = new Dictionary(); - CrestronConsole.AddNewConsoleCommand(GenerateClientToken, "MobileAddUiClient", "Adds a client and generates a token. ? for more help", ConsoleAccessLevelEnum.AccessOperator); + if (Global.Platform == eDevicePlatform.Appliance) + { + AddConsoleCommands(); + } + + AddPreActivationAction(() => AddWebApiPaths()); + } + + private void AddWebApiPaths() + { + var apiServer = DeviceManager.AllDevices.OfType().FirstOrDefault(); + + if (apiServer == null) + { + Debug.Console(0, this, "No API Server available"); + return; + } + + var routes = new List + { + new HttpCwsRoute($"devices/{Key}/client") + { + Name = "ClientHandler", + RouteHandler = new UiClientHandler(this) + }, + }; + + apiServer.AddRoute(routes); + } + + private void AddConsoleCommands() + { + CrestronConsole.AddNewConsoleCommand(GenerateClientTokenFromConsole, "MobileAddUiClient", "Adds a client and generates a token. ? for more help", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(RemoveToken, "MobileRemoveUiClient", "Removes a client. ? for more help", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand((s) => PrintClientInfo(), "MobileGetClientInfo", "Displays the current client info", ConsoleAccessLevelEnum.AccessOperator); } @@ -250,7 +296,7 @@ public override void Initialize() if (_parent.Config.DirectServer.Logging.EnableRemoteLogging) { - _server.OnPost += Server_OnPost; + _server.OnPost += Server_OnPost; } CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; @@ -267,6 +313,69 @@ public override void Initialize() RetrieveSecret(); CreateFolderStructure(); + + AddClientsForTouchpanels(); + } + + private void AddClientsForTouchpanels() + { + var touchpanels = DeviceManager.AllDevices + .OfType().Where(tp => tp.UseDirectServer); + + + var newTouchpanels = touchpanels.Where(tp => !_secret.Tokens.Any(t => t.Value.TouchpanelKey != null && t.Value.TouchpanelKey.Equals(tp.Key, StringComparison.InvariantCultureIgnoreCase))); + + + foreach (var client in newTouchpanels) + { + var bridge = _parent.GetRoomBridge(client.DefaultRoomKey); + + if (bridge == null) + { + Debug.Console(0, this, $"Unable to find room with key: {client.DefaultRoomKey}"); + return; + } + + var (key, path) = GenerateClientToken(bridge, client.Key); + + if (key == null) + { + Debug.Console(0, this, $"Unable to generate a client for {client.Key}"); + continue; + } + } + + foreach (var touchpanel in touchpanels.Select(tp => + { + var token = _secret.Tokens.FirstOrDefault((t) => t.Value.TouchpanelKey.Equals(tp.Key, StringComparison.InvariantCultureIgnoreCase)); + + var messenger = _parent.GetRoomBridge(tp.DefaultRoomKey); + + return new { token.Key, Touchpanel = tp, Messenger = messenger }; + })) + { + if (touchpanel.Key == null) + { + Debug.Console(0, this, $"Token for touchpanel {touchpanel.Touchpanel.Key} not found"); + continue; + } + + if (touchpanel.Messenger == null) + { + Debug.Console(2, this, $"Unable to find room messenger for {touchpanel.Touchpanel.DefaultRoomKey}"); + continue; + } + + var lanAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter); + + var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, lanAdapterId); + + var appUrl = $"http://{processorIp}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"; + + Debug.Console(2, this, $"Sending URL {appUrl}"); + + touchpanel.Messenger.UpdateAppUrl($"http://{processorIp}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"); + } } private void OnProgramStop(eProgramStatusEventType programEventType) @@ -275,22 +384,23 @@ private void OnProgramStop(eProgramStatusEventType programEventType) { case eProgramStatusEventType.Stopping: _server.Stop(); - break; + break; } } private void CreateFolderStructure() { - if (!Directory.Exists(userAppPath)) { - Directory.Create(userAppPath); + if (!Directory.Exists(userAppPath)) + { + Directory.CreateDirectory(userAppPath); } if (!Directory.Exists($"{userAppPath}{localConfigFolderName}")) { - Directory.Create($"{userAppPath}{localConfigFolderName}"); + Directory.CreateDirectory($"{userAppPath}{localConfigFolderName}"); } - using(var sw = new StreamWriter(File.Open($"{userAppPath}{localConfigFolderName}{Global.DirectorySeparator}{appConfigFileName}", FileMode.Truncate, FileAccess.ReadWrite))) + using (var sw = new StreamWriter(File.Open($"{userAppPath}{localConfigFolderName}{Global.DirectorySeparator}{appConfigFileName}", FileMode.Create, FileAccess.ReadWrite))) { var config = GetApplicationConfig(); @@ -331,7 +441,7 @@ private MobileControlApplicationConfig GetApplicationConfig() } } }, - Logging = _parent.Config.DirectServer.Logging.EnableRemoteLogging, + Logging = _parent.Config.DirectServer.Logging.EnableRemoteLogging, }; } else @@ -358,7 +468,8 @@ private MobileControlApplicationConfig GetApplicationConfig() Logging = _parent.Config.ApplicationConfig.Logging }; } - } catch(Exception ex) + } + catch (Exception ex) { Debug.Console(0, this, "Error getting application configuration: {0}", ex.Message); Debug.Console(2, this, "Stack Trace: {0}", ex.StackTrace); @@ -375,10 +486,10 @@ private MobileControlApplicationConfig GetApplicationConfig() private void RetrieveSecret() { // Add secret provider - _secretProvider = new WebSocketServerSecretProvider(_secretProviderKey); + _secretProvider = new WebSocketServerSecretProvider(SecretProviderKey); // Check for existing secrets - var secret = _secretProvider.GetSecret(_secretProviderKey); + var secret = _secretProvider.GetSecret(SecretProviderKey); if (secret != null) { @@ -430,9 +541,8 @@ private void RetrieveSecret() /// /// Stores secrets to memory to persist through reboot /// - private void UpdateSecret() + public void UpdateSecret() { - _secret.Tokens.Clear(); foreach (var uiClientContext in UiClients) @@ -442,14 +552,14 @@ private void UpdateSecret() var serializedSecret = JsonConvert.SerializeObject(_secret); - _secretProvider.SetSecret(_secretProviderKey, serializedSecret); + _secretProvider.SetSecret(SecretProviderKey, serializedSecret); } /// /// Generates a new token based on validating a room key and grant code passed in. If valid, returns a token and adds a service to the server for that token's path /// /// - private void GenerateClientToken(string s) + private void GenerateClientTokenFromConsole(string s) { if (s == "?" || string.IsNullOrEmpty(s)) { @@ -461,58 +571,88 @@ private void GenerateClientToken(string s) var roomKey = values[0]; var grantCode = values[1]; + var bridge = _parent.GetRoomBridge(roomKey); + + if (bridge == null) + { + CrestronConsole.ConsoleCommandResponse(string.Format("Unable to find room with key: {0}", roomKey)); + return; + } + + var (token, path) = ValidateGrantCode(grantCode, bridge); + + if (token == null) + { + CrestronConsole.ConsoleCommandResponse("Grant Code is not valid"); + return; + } + + CrestronConsole.ConsoleCommandResponse($"Added new WebSocket UiClient service at path: {path}"); + CrestronConsole.ConsoleCommandResponse($"Token: {token}"); + } + + public (string, string) ValidateGrantCode(string grantCode, string roomKey) + { + var bridge = _parent.GetRoomBridge(roomKey); + + if (bridge == null) + { + Debug.Console(0, this, $"Unable to find room with key: {roomKey}"); + return (null, null); + } + + return ValidateGrantCode(grantCode, bridge); + } + + public (string, string) ValidateGrantCode(string grantCode, MobileControlBridgeBase bridge) + { // TODO: Authenticate grant code passed in // For now, we just generate a random guid as the token and use it as the ClientId as well - var grantCodeIsValid = true; if (grantCodeIsValid) { - if (_secret == null) { _secret = new ServerTokenSecrets(grantCode); } - var bridge = _parent.GetRoomBridge(roomKey); - if (bridge != null) - { - var key = Guid.NewGuid().ToString(); + return GenerateClientToken(bridge, ""); + } + else + { + return (null, null); + } + } - var token = new JoinToken() { Code = bridge.UserCode, RoomKey = bridge.RoomKey, Uuid = _parent.SystemUuid }; + public (string, string) GenerateClientToken(MobileControlBridgeBase bridge, string touchPanelKey = "") + { + var key = Guid.NewGuid().ToString(); - UiClients.Add(key, new UiClientContext(token)); + var token = new JoinToken { Code = bridge.UserCode, RoomKey = bridge.RoomKey, Uuid = _parent.SystemUuid, TouchpanelKey = touchPanelKey }; - var path = _wsPath + key; + UiClients.Add(key, new UiClientContext(token)); - _server.AddWebSocketService(path, () => - { - var c = new UiClient(); - Debug.Console(2, this, "Constructing UiClient with id: {0}", key); - c.Controller = _parent; - c.RoomKey = roomKey; - UiClients[key].SetClient(c); - return c; - }); + var path = _wsPath + key; + _server.AddWebSocketService(path, () => + { + var c = new UiClient(); + Debug.Console(2, this, "Constructing UiClient with id: {0}", key); + c.Controller = _parent; + c.RoomKey = bridge.RoomKey; + UiClients[key].SetClient(c); + return c; + }); - CrestronConsole.ConsoleCommandResponse("Added new WebSocket UiClient service at path: {0}", path); + Debug.Console(0, this, $"Added new WebSocket UiClient service at path: {path}"); + Debug.Console(0, this, $"Token: {key}"); - Debug.Console(2, this, "{0} websocket services present", _server.WebSocketServices.Count); + Debug.Console(2, this, "{0} websocket services present", _server.WebSocketServices.Count); - CrestronConsole.ConsoleCommandResponse(string.Format("Token: {0}", key)); + UpdateSecret(); - UpdateSecret(); - } - else - { - CrestronConsole.ConsoleCommandResponse(string.Format("Unable to find room with key: {0}", roomKey)); - } - } - else - { - CrestronConsole.ConsoleCommandResponse("Grant Code is not valid"); - } + return (key, path); } /// @@ -529,8 +669,8 @@ private void RemoveToken(string s) var key = s; - if(UiClients.ContainsKey(key)) - { + if (UiClients.ContainsKey(key)) + { var uiClientContext = UiClients[key]; if (uiClientContext.Client != null && uiClientContext.Client.Context.WebSocket.IsAlive) @@ -577,7 +717,7 @@ private void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventTy { if (programEventType == eProgramStatusEventType.Stopping) { - foreach(var client in UiClients.Values) + foreach (var client in UiClients.Values) { if (client.Client != null && client.Client.Context.WebSocket.IsAlive) { @@ -646,13 +786,13 @@ private async void Server_OnPost(object sender, HttpRequestEventArgs e) res.AddHeader("Access-Control-Allow-Origin", "*"); var path = req.RawUrl; - var ip = req.RemoteEndPoint.Address.ToString(); + var ip = req.RemoteEndPoint.Address.ToString(); - Debug.Console(2, this, "POST Request received at path: {0} from host {1}", path, ip); + Debug.Console(2, this, "POST Request received at path: {0} from host {1}", path, ip); var body = new System.IO.StreamReader(req.InputStream).ReadToEnd(); - if(path.StartsWith("/mc/api/log")) + if (path.StartsWith("/mc/api/log")) { res.StatusCode = 200; res.Close(); @@ -667,10 +807,11 @@ private async void Server_OnPost(object sender, HttpRequestEventArgs e) await LogClient.SendAsync(logRequest); Debug.Console(2, this, "Log data sent to {0}:{1}", _parent.Config.DirectServer.Logging.Host, _parent.Config.DirectServer.Logging.Port); - } else + } + else { res.StatusCode = 404; - res.Close(); + res.Close(); } } catch (Exception ex) @@ -678,7 +819,7 @@ private async void Server_OnPost(object sender, HttpRequestEventArgs e) Debug.Console(0, Debug.ErrorLogLevel.Error, "Caught an exception in the OnPost handler {0}", ex.Message); Debug.Console(2, Debug.ErrorLogLevel.Error, "StackTrace: {0}", ex.StackTrace); - if(ex.InnerException != null) + if (ex.InnerException != null) { Debug.Console(0, Debug.ErrorLogLevel.Error, "Caught an exception in the OnGet handler {0}", ex.InnerException.Message); Debug.Console(2, Debug.ErrorLogLevel.Error, "StackTrace: {0}", ex.InnerException.StackTrace); @@ -689,7 +830,7 @@ private async void Server_OnPost(object sender, HttpRequestEventArgs e) private void Server_OnOptions(object sender, HttpRequestEventArgs e) { try - { + { var res = e.Response; res.AddHeader("Access-Control-Allow-Origin", "*"); @@ -697,7 +838,7 @@ private void Server_OnOptions(object sender, HttpRequestEventArgs e) res.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me"); res.StatusCode = 200; - res.Close(); + res.Close(); } catch (Exception ex) { @@ -725,9 +866,8 @@ private void HandleJoinRequest(HttpListenerRequest req, HttpListenerResponse res Debug.Console(2, this, "Join Room Request with token: {0}", token); - UiClientContext clientContext = null; - if (UiClients.TryGetValue(token, out clientContext)) + if (UiClients.TryGetValue(token, out UiClientContext clientContext)) { var bridge = _parent.GetRoomBridge(clientContext.Token.RoomKey); @@ -737,18 +877,20 @@ private void HandleJoinRequest(HttpListenerRequest req, HttpListenerResponse res res.ContentType = "application/json"; // Construct the response object - JoinResponse jRes = new JoinResponse(); - jRes.ClientId = token; - jRes.RoomKey = bridge.RoomKey; - jRes.SystemUuid = _parent.SystemUuid; - jRes.RoomUuid = _parent.SystemUuid; - jRes.Config = _parent.GetConfigWithPluginVersion(); - jRes.CodeExpires = new DateTime().AddYears(1); - jRes.UserCode = bridge.UserCode; - jRes.UserAppUrl = string.Format("http://{0}:{1}/mc/app", + JoinResponse jRes = new JoinResponse + { + ClientId = token, + RoomKey = bridge.RoomKey, + SystemUuid = _parent.SystemUuid, + RoomUuid = _parent.SystemUuid, + Config = _parent.GetConfigWithPluginVersion(), + CodeExpires = new DateTime().AddYears(1), + UserCode = bridge.UserCode, + UserAppUrl = string.Format("http://{0}:{1}/mc/app", CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0), - Port); - jRes.EnableDebug = false; + Port), + EnableDebug = false + }; // Serialize to JSON and convert to Byte[] var json = JsonConvert.SerializeObject(jRes); @@ -900,7 +1042,7 @@ public void StopServer() public void SendMessageToAllClients(string message) { foreach (var clientContext in UiClients.Values) - { + { if (clientContext.Client != null && clientContext.Client.Context.WebSocket.IsAlive) { clientContext.Client.Context.WebSocket.Send(message); @@ -915,9 +1057,12 @@ public void SendMessageToAllClients(string message) /// public void SendMessageToClient(object clientId, string message) { - UiClientContext clientContext; + if (clientId == null) + { + return; + } - if (UiClients.TryGetValue((string)clientId, out clientContext)) + if (UiClients.TryGetValue((string)clientId, out UiClientContext clientContext)) { if (clientContext.Client != null) { @@ -999,6 +1144,10 @@ public class JoinToken public string RoomKey { get; set; } public string Uuid { get; set; } + + public string TouchpanelKey { get; set; } = ""; + + public string Token { get; set; } = null; } /// diff --git a/4-series/epi-essentials-mobile-control/WebSocketServer/WebSocketServerSecretProvider.cs b/4-series/epi-essentials-mobile-control/WebSocketServer/WebSocketServerSecretProvider.cs index 8033881..7aa4099 100644 --- a/4-series/epi-essentials-mobile-control/WebSocketServer/WebSocketServerSecretProvider.cs +++ b/4-series/epi-essentials-mobile-control/WebSocketServer/WebSocketServerSecretProvider.cs @@ -1,19 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - +using Newtonsoft.Json; using PepperDash.Essentials.Core; -using Newtonsoft.Json; - namespace PepperDash.Essentials { - class WebSocketServerSecretProvider : CrestronLocalSecretsProvider + internal class WebSocketServerSecretProvider : CrestronLocalSecretsProvider { public WebSocketServerSecretProvider(string key) - :base(key) + : base(key) { Key = key; } diff --git a/4-series/epi-essentials-mobile-control/epi-essentials-mobile-control.csproj b/4-series/epi-essentials-mobile-control/epi-essentials-mobile-control.csproj index 1e81e82..2bb7c9b 100644 --- a/4-series/epi-essentials-mobile-control/epi-essentials-mobile-control.csproj +++ b/4-series/epi-essentials-mobile-control/epi-essentials-mobile-control.csproj @@ -28,7 +28,7 @@ TRACE;SERIES4 - + @@ -43,7 +43,6 @@ - diff --git a/4-series/mobile-control-messengers/ContentTypes.cs b/4-series/mobile-control-messengers/ContentTypes.cs index 9a1d422..7945e71 100644 --- a/4-series/mobile-control-messengers/ContentTypes.cs +++ b/4-series/mobile-control-messengers/ContentTypes.cs @@ -1,21 +1,24 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Newtonsoft.Json; +using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer { public class SourceSelectMessageContent { - public string SourceListItem { get; set; } + [JsonProperty("sourceListItemKey")] + public string SourceListItemKey { get; set; } + [JsonProperty("sourceListKey")] public string SourceListKey { get; set; } } public class DirectRoute { + [JsonProperty("sourceKey")] public string SourceKey { get; set; } + [JsonProperty("destinationKey")] public string DestinationKey { get; set; } + [JsonProperty("signalType")] + public eRoutingSignalType SignalType { get; set; } } /// diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/CoreDisplayBaseMessenger.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/CoreDisplayBaseMessenger.cs new file mode 100644 index 0000000..bf78271 --- /dev/null +++ b/4-series/mobile-control-messengers/DeviceTypeExtenstions/CoreDisplayBaseMessenger.cs @@ -0,0 +1,61 @@ +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using PepperDash.Essentials.AppServer; +using PepperDash.Essentials.AppServer.Messengers; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using System; +using System.Linq; +using DisplayBase = PepperDash.Essentials.Core.DisplayBase; + +namespace PepperDash.Essentials.Room.MobileControl +{ + public class CoreDisplayBaseMessenger: MessengerBase + { + private readonly DisplayBase display; + + public CoreDisplayBaseMessenger(string key, string messagePath, DisplayBase device) : base(key, messagePath, device) + { + display = device; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + /* AddAction("/powerOn", (id, content) => display.PowerOn()); + AddAction("/powerOff", (id, content) => display.PowerOff()); + AddAction("/powerToggle", (id, content) => display.PowerToggle());*/ + + AddAction("/inputSelect", (id, content) => + { + var s = content.ToObject>(); + + var inputPort = display.InputPorts.FirstOrDefault(i => i.Key == s.Value); + + if (inputPort == null) + { + Debug.Console(1, "No input named {0} found for device {1}", s, display.Key); + return; + } + + display.ExecuteSwitch(inputPort.Selector); + }); + + AddAction("/inputs", (id, content) => + { + var inputsList = display.InputPorts.Select(p => p.Key).ToList(); + + var messageObject = new MobileControlMessage + { + Type = MessagePath + "/inputs", + Content = JToken.FromObject(new + { + inputKeys = inputsList, + }) + }; + + AppServerController.SendMessageObject(messageObject); + }); + } + } +} diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/DisplayBaseExtensions.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/DisplayBaseExtensions.cs deleted file mode 100644 index 571500e..0000000 --- a/4-series/mobile-control-messengers/DeviceTypeExtenstions/DisplayBaseExtensions.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Linq; -using PepperDash.Core; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.DeviceTypeInterfaces; - -namespace PepperDash.Essentials.Room.MobileControl -{ - public static class DisplayBaseExtensions - { - public static void LinkActions(this DisplayBase display, IMobileControl3 controller) - { - var prefix = String.Format(@"/device/{0}/", display.Key); - - controller.AddAction(prefix + "powerOn", new Action(display.PowerOn)); - controller.AddAction(prefix + "powerOff", new Action(display.PowerOff)); - controller.AddAction(prefix + "powerToggle", new Action(display.PowerToggle)); - - controller.AddAction(prefix + "inputSelect", new Action((s) => - { - var inputPort = display.InputPorts.FirstOrDefault(i => i.Key == s); - - if (inputPort == null) - { - Debug.Console(1, "No input named {0} found for device {1}", s, display.Key); - return; - } - - display.ExecuteSwitch(inputPort.Selector); - })); - - controller.AddAction(prefix + "inputs", new Action(() => - { - var inputsList = display.InputPorts.Select(p => p.Key).ToList(); - - var messageObject = new - { - type = prefix + "inputs", - content = new - { - inputKeys = inputsList, - } - }; - - controller.SendMessageObject(messageObject); - })); - } - - public static void UnlinkActions(this DisplayBase display, IMobileControl3 controller) - { - var prefix = String.Format(@"/device/{0}/", display.Key); - - controller.RemoveAction(prefix + "powerOn"); - controller.RemoveAction(prefix + "powerOff"); - controller.RemoveAction(prefix + "powerToggle"); - controller.RemoveAction(prefix + "inputs"); - controller.RemoveAction(prefix + "inputSelect"); - } - } -} \ No newline at end of file diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/DisplayBaseMessenger.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/DisplayBaseMessenger.cs new file mode 100644 index 0000000..659c62e --- /dev/null +++ b/4-series/mobile-control-messengers/DeviceTypeExtenstions/DisplayBaseMessenger.cs @@ -0,0 +1,61 @@ +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using PepperDash.Essentials.AppServer; +using PepperDash.Essentials.AppServer.Messengers; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using System; +using System.Linq; +using DisplayBase = PepperDash.Essentials.Devices.Common.Displays.DisplayBase; + +namespace PepperDash.Essentials.Room.MobileControl +{ + public class DisplayBaseMessenger: MessengerBase + { + private readonly DisplayBase display; + + public DisplayBaseMessenger(string key, string messagePath, DisplayBase device) : base(key, messagePath, device) + { + display = device; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + /*AddAction("/powerOn", (id, content) => display.PowerOn()); + AddAction("/powerOff", (id, content) => display.PowerOff()); + AddAction("/powerToggle", (id, content) => display.PowerToggle());*/ + + AddAction("/inputSelect", (id, content) => + { + var s = content.ToObject>(); + + var inputPort = display.InputPorts.FirstOrDefault(i => i.Key == s.Value); + + if (inputPort == null) + { + Debug.Console(1, "No input named {0} found for device {1}", s, display.Key); + return; + } + + display.ExecuteSwitch(inputPort.Selector); + }); + + AddAction("/inputs", (id, content) => + { + var inputsList = display.InputPorts.Select(p => p.Key).ToList(); + + var messageObject = new MobileControlMessage + { + Type = MessagePath + "/inputs", + Content = JToken.FromObject(new + { + inputKeys = inputsList, + }) + }; + + AppServerController.SendMessageObject(messageObject); + }); + } + } +} diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/IChannelExtensions.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/IChannelExtensions.cs deleted file mode 100644 index 701230f..0000000 --- a/4-series/mobile-control-messengers/DeviceTypeExtenstions/IChannelExtensions.cs +++ /dev/null @@ -1,35 +0,0 @@ -using PepperDash.Essentials.Core; -using PepperDash.Core; -using PepperDash.Essentials.Core.DeviceTypeInterfaces; -#if SERIES4 -using PepperDash.Essentials.AppServer; -#endif -namespace PepperDash.Essentials.Room.MobileControl -{ - public static class ChannelExtensions - { - public static void LinkActions(this IChannel dev, IMobileControl3 controller) - { - var prefix = string.Format(@"/device/{0}/", ((IKeyed) dev).Key); - - controller.AddAction(prefix + "chanUp", new PressAndHoldAction(dev.ChannelUp)); - controller.AddAction(prefix + "chanDown", new PressAndHoldAction(dev.ChannelDown)); - controller.AddAction(prefix + "lastChan", new PressAndHoldAction(dev.LastChannel)); - controller.AddAction(prefix + "guide", new PressAndHoldAction(dev.Guide)); - controller.AddAction(prefix + "info", new PressAndHoldAction(dev.Info)); - controller.AddAction(prefix + "exit", new PressAndHoldAction(dev.Exit)); - } - - public static void UnlinkActions(this IChannel dev, IMobileControl3 controller) - { - var prefix = string.Format(@"/device/{0}/", ((IKeyed) dev).Key); - - controller.RemoveAction(prefix + "chanUp"); - controller.RemoveAction(prefix + "chanDown"); - controller.RemoveAction(prefix + "lastChan"); - controller.RemoveAction(prefix + "guide"); - controller.RemoveAction(prefix + "info"); - controller.RemoveAction(prefix + "exit"); - } - } -} \ No newline at end of file diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/IChannelMessenger.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/IChannelMessenger.cs new file mode 100644 index 0000000..fa5b098 --- /dev/null +++ b/4-series/mobile-control-messengers/DeviceTypeExtenstions/IChannelMessenger.cs @@ -0,0 +1,31 @@ +using PepperDash.Core; +using PepperDash.Essentials.AppServer.Messengers; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +#if SERIES4 +#endif +namespace PepperDash.Essentials.Room.MobileControl +{ + public class IChannelMessenger:MessengerBase + { + private readonly IChannel channelDevice; + + public IChannelMessenger(string key, string messagePath, Device device) : base(key, messagePath, device) + { + channelDevice = device as IChannel; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/chanUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => channelDevice?.ChannelUp(b))); + + AddAction("/chanDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => channelDevice?.ChannelDown(b))); + AddAction("/lastChan", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => channelDevice?.LastChannel(b))); + AddAction("/guide", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => channelDevice?.Guide(b))); + AddAction("/info", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => channelDevice?.Info(b))); + AddAction("/exit", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => channelDevice?.Exit(b))); + } + } +} \ No newline at end of file diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/IColorExtensions.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/IColorExtensions.cs deleted file mode 100644 index 5210eb2..0000000 --- a/4-series/mobile-control-messengers/DeviceTypeExtenstions/IColorExtensions.cs +++ /dev/null @@ -1,33 +0,0 @@ -using PepperDash.Essentials.Core; -using PepperDash.Core; -using PepperDash.Essentials.Core.DeviceTypeInterfaces; -#if SERIES4 -using PepperDash.Essentials.AppServer; -#endif - - -namespace PepperDash.Essentials.Room.MobileControl -{ - public static class ColorExtensions - { - public static void LinkActions(this IColor dev, IMobileControl3 controller) - { - var prefix = string.Format(@"/device/{0}/", ((IKeyed) dev).Key); - - controller.AddAction(prefix + "red", new PressAndHoldAction(dev.Red)); - controller.AddAction(prefix + "green", new PressAndHoldAction(dev.Green)); - controller.AddAction(prefix + "yellow", new PressAndHoldAction(dev.Yellow)); - controller.AddAction(prefix + "blue", new PressAndHoldAction(dev.Blue)); - } - - public static void UnlinkActions(this IColor dev, IMobileControl3 controller) - { - var prefix = string.Format(@"/device/{0}/", ((IKeyed) dev).Key); - - controller.RemoveAction(prefix + "red"); - controller.RemoveAction(prefix + "green"); - controller.RemoveAction(prefix + "yellow"); - controller.RemoveAction(prefix + "blue"); - } - } -} \ No newline at end of file diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/IColorMessenger.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/IColorMessenger.cs new file mode 100644 index 0000000..04e64d9 --- /dev/null +++ b/4-series/mobile-control-messengers/DeviceTypeExtenstions/IColorMessenger.cs @@ -0,0 +1,26 @@ +using PepperDash.Core; +using PepperDash.Essentials.AppServer.Messengers; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; + +namespace PepperDash.Essentials.Room.MobileControl +{ + public class IColorMessenger:MessengerBase + { + private readonly IColor colorDevice; + public IColorMessenger(string key, string messagePath, Device device) : base(key, messagePath, device) + { + colorDevice = device as IColor; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/red", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => colorDevice?.Red(b))); + AddAction("/green", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => colorDevice?.Green(b))); + AddAction("/yellow", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => colorDevice?.Yellow(b))); + AddAction("/blue", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => colorDevice?.Blue(b))); + } + } +} \ No newline at end of file diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/IDPadExtensions.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/IDPadExtensions.cs deleted file mode 100644 index 87ff38e..0000000 --- a/4-series/mobile-control-messengers/DeviceTypeExtenstions/IDPadExtensions.cs +++ /dev/null @@ -1,37 +0,0 @@ -using PepperDash.Core; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.DeviceTypeInterfaces; -#if SERIES4 -using PepperDash.Essentials.AppServer; -#endif -namespace PepperDash.Essentials.Room.MobileControl -{ - public static class IdPadExtensions - { - public static void LinkActions(this IDPad dev, IMobileControl3 controller) - { - var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); - - controller.AddAction(prefix + "up", new PressAndHoldAction(dev.Up)); - controller.AddAction(prefix + "down", new PressAndHoldAction(dev.Down)); - controller.AddAction(prefix + "left", new PressAndHoldAction(dev.Left)); - controller.AddAction(prefix + "right", new PressAndHoldAction(dev.Right)); - controller.AddAction(prefix + "select", new PressAndHoldAction(dev.Select)); - controller.AddAction(prefix + "menu", new PressAndHoldAction(dev.Menu)); - controller.AddAction(prefix + "exit", new PressAndHoldAction(dev.Exit)); - } - - public static void UnlinkActions(this IDPad dev, IMobileControl3 controller) - { - var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); - - controller.RemoveAction(prefix + "up"); - controller.RemoveAction(prefix + "down"); - controller.RemoveAction(prefix + "left"); - controller.RemoveAction(prefix + "right"); - controller.RemoveAction(prefix + "select"); - controller.RemoveAction(prefix + "menu"); - controller.RemoveAction(prefix + "exit"); - } - } -} \ No newline at end of file diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/IDPadMessenger.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/IDPadMessenger.cs new file mode 100644 index 0000000..251ff87 --- /dev/null +++ b/4-series/mobile-control-messengers/DeviceTypeExtenstions/IDPadMessenger.cs @@ -0,0 +1,31 @@ +using PepperDash.Core; +using PepperDash.Essentials.AppServer.Messengers; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +#if SERIES4 +#endif +namespace PepperDash.Essentials.Room.MobileControl +{ + public class IDPadMessenger:MessengerBase + { + private readonly IDPad dpadDevice; + public IDPadMessenger(string key, string messagePath, Device device) : base(key, messagePath, device) + { + dpadDevice = device as IDPad; + } + + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/up", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => dpadDevice?.Up(b))); + AddAction("/down", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => dpadDevice?.Down(b))); + AddAction("/left", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => dpadDevice?.Left(b))); + AddAction("/right", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => dpadDevice?.Right(b))); + AddAction("/select", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => dpadDevice?.Select(b))); + AddAction("/menu", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => dpadDevice?.Menu(b))); + AddAction("/exit", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => dpadDevice?.Exit(b))); + } + } +} \ No newline at end of file diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/IDvrExtensions.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/IDvrExtensions.cs deleted file mode 100644 index e9941c5..0000000 --- a/4-series/mobile-control-messengers/DeviceTypeExtenstions/IDvrExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -using PepperDash.Essentials.Core; -using PepperDash.Core; -using PepperDash.Essentials.Core.DeviceTypeInterfaces; -#if SERIES4 -using PepperDash.Essentials.AppServer; -#endif -namespace PepperDash.Essentials.Room.MobileControl -{ - public static class DvrExtensions - { - public static void LinkActions(this IDvr dev, IMobileControl3 controller) - { - var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); - - controller.AddAction(prefix + "dvrlist", new PressAndHoldAction(dev.DvrList)); - controller.AddAction(prefix + "record", new PressAndHoldAction(dev.Record)); - } - - public static void UnlinkActions(this IDvr dev, IMobileControl3 controller) - { - var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); - - controller.RemoveAction(prefix + "dvrlist"); - controller.RemoveAction(prefix + "record"); - } - } -} \ No newline at end of file diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/IDvrMessenger.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/IDvrMessenger.cs new file mode 100644 index 0000000..399c113 --- /dev/null +++ b/4-series/mobile-control-messengers/DeviceTypeExtenstions/IDvrMessenger.cs @@ -0,0 +1,26 @@ +using PepperDash.Core; +using PepperDash.Essentials.AppServer.Messengers; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +#if SERIES4 +#endif +namespace PepperDash.Essentials.Room.MobileControl +{ + public class IDvrMessenger: MessengerBase + { + private readonly IDvr dvrDevice; + public IDvrMessenger(string key, string messagePath, Device device) : base(key, messagePath, device) + { + dvrDevice = device as IDvr; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/dvrlist", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => dvrDevice?.DvrList(b))); + AddAction("/record", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => dvrDevice?.Record(b))); + } + + } +} \ No newline at end of file diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/IHasPowerExtensions.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/IHasPowerExtensions.cs deleted file mode 100644 index e033c76..0000000 --- a/4-series/mobile-control-messengers/DeviceTypeExtenstions/IHasPowerExtensions.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using PepperDash.Essentials.Core; -using PepperDash.Core; -using PepperDash.Essentials.Core.DeviceTypeInterfaces; - -namespace PepperDash.Essentials.Room.MobileControl -{ - public static class HasPowerExtensions - { - public static void LinkActions(this IHasPowerControl dev, IMobileControl3 controller) - { - var prefix = string.Format(@"/device/{0}/", ((IKeyed) dev).Key); - - controller.AddAction(prefix + "powerOn", new Action(dev.PowerOn)); - controller.AddAction(prefix + "powerOff", new Action(dev.PowerOff)); - controller.AddAction(prefix + "powerToggle", new Action(dev.PowerToggle)); - } - - public static void UnlinkActions(this IHasPowerControl dev, IMobileControl3 controller) - { - var prefix = string.Format(@"/device/{0}/", ((IKeyed) dev).Key); - - controller.RemoveAction(prefix + "powerOn"); - controller.RemoveAction(prefix + "powerOff"); - controller.RemoveAction(prefix + "powerToggle"); - } - } -} \ No newline at end of file diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/IHasPowerMessenger.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/IHasPowerMessenger.cs new file mode 100644 index 0000000..33ce7ea --- /dev/null +++ b/4-series/mobile-control-messengers/DeviceTypeExtenstions/IHasPowerMessenger.cs @@ -0,0 +1,25 @@ +using PepperDash.Core; +using PepperDash.Essentials.AppServer.Messengers; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; + +namespace PepperDash.Essentials.Room.MobileControl +{ + public class IHasPowerMessenger:MessengerBase + { + private readonly IHasPowerControl powerDevice; + public IHasPowerMessenger(string key, string messagePath, Device device) : base(key, messagePath, device) + { + powerDevice = device as IHasPowerControl; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/powerOn", (id, content) => powerDevice?.PowerOn()); + AddAction("/powerOff", (id, content) => powerDevice?.PowerOff()); + AddAction("/powerToggle", (id, content) => powerDevice?.PowerToggle()); + } + } +} \ No newline at end of file diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/INumericExtensions.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/INumericExtensions.cs deleted file mode 100644 index 7cc9ada..0000000 --- a/4-series/mobile-control-messengers/DeviceTypeExtenstions/INumericExtensions.cs +++ /dev/null @@ -1,48 +0,0 @@ -using PepperDash.Essentials.Core; -using PepperDash.Core; -using PepperDash.Essentials.Core.DeviceTypeInterfaces; -#if SERIES4 -using PepperDash.Essentials.AppServer; -#endif -namespace PepperDash.Essentials.Room.MobileControl -{ - public static class NumericExtensions - { - public static void LinkActions(this INumericKeypad dev, IMobileControl3 controller) - { - var prefix = string.Format(@"/device/{0}/", ((IKeyed) dev).Key); - - controller.AddAction(prefix + "num0", new PressAndHoldAction(dev.Digit0)); - controller.AddAction(prefix + "num1", new PressAndHoldAction(dev.Digit1)); - controller.AddAction(prefix + "num2", new PressAndHoldAction(dev.Digit2)); - controller.AddAction(prefix + "num3", new PressAndHoldAction(dev.Digit3)); - controller.AddAction(prefix + "num4", new PressAndHoldAction(dev.Digit4)); - controller.AddAction(prefix + "num5", new PressAndHoldAction(dev.Digit5)); - controller.AddAction(prefix + "num6", new PressAndHoldAction(dev.Digit6)); - controller.AddAction(prefix + "num7", new PressAndHoldAction(dev.Digit7)); - controller.AddAction(prefix + "num8", new PressAndHoldAction(dev.Digit8)); - controller.AddAction(prefix + "num9", new PressAndHoldAction(dev.Digit9)); - controller.AddAction(prefix + "numDash", new PressAndHoldAction(dev.KeypadAccessoryButton1)); - controller.AddAction(prefix + "numEnter", new PressAndHoldAction(dev.KeypadAccessoryButton2)); - // Deal with the Accessory functions on the numpad later - } - - public static void UnlinkActions(this INumericKeypad dev, IMobileControl3 controller) - { - var prefix = string.Format(@"/device/{0}/", ((IKeyed) dev).Key); - - controller.RemoveAction(prefix + "num0"); - controller.RemoveAction(prefix + "num1"); - controller.RemoveAction(prefix + "num2"); - controller.RemoveAction(prefix + "num3"); - controller.RemoveAction(prefix + "num4"); - controller.RemoveAction(prefix + "num5"); - controller.RemoveAction(prefix + "num6"); - controller.RemoveAction(prefix + "num7"); - controller.RemoveAction(prefix + "num8"); - controller.RemoveAction(prefix + "num9"); - controller.RemoveAction(prefix + "numDash"); - controller.RemoveAction(prefix + "numEnter"); - } - } -} \ No newline at end of file diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/INumericMessenger.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/INumericMessenger.cs new file mode 100644 index 0000000..47cf829 --- /dev/null +++ b/4-series/mobile-control-messengers/DeviceTypeExtenstions/INumericMessenger.cs @@ -0,0 +1,36 @@ +using PepperDash.Core; +using PepperDash.Essentials.AppServer.Messengers; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +#if SERIES4 +#endif +namespace PepperDash.Essentials.Room.MobileControl +{ + public class INumericKeypadMessenger:MessengerBase + { + private readonly INumericKeypad keypadDevice; + public INumericKeypadMessenger(string key, string messagePath, Device device) : base(key, messagePath, device) + { + keypadDevice = device as INumericKeypad; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/num0", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => keypadDevice?.Digit0(b))); + AddAction("/num1", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => keypadDevice?.Digit1(b))); + AddAction("/num2", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => keypadDevice?.Digit2(b))); + AddAction("/num3", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => keypadDevice?.Digit3(b))); + AddAction("/num4", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => keypadDevice?.Digit4(b))); + AddAction("/num5", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => keypadDevice?.Digit5(b))); + AddAction("/num6", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => keypadDevice?.Digit6(b))); + AddAction("/num7", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => keypadDevice?.Digit7(b))); + AddAction("/num8", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => keypadDevice?.Digit8(b))); + AddAction("/num9", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => keypadDevice?.Digit9(b))); + AddAction("/numDash", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => keypadDevice?.KeypadAccessoryButton1(b))); + AddAction("/numEnter", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => keypadDevice?.KeypadAccessoryButton2(b))); + // Deal with the Accessory functions on the numpad later + } + } +} \ No newline at end of file diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/ISetTopBoxControlsExtensions.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/ISetTopBoxControlsExtensions.cs deleted file mode 100644 index 6064941..0000000 --- a/4-series/mobile-control-messengers/DeviceTypeExtenstions/ISetTopBoxControlsExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -using PepperDash.Essentials.Core; -using PepperDash.Core; -using PepperDash.Essentials.Core.DeviceTypeInterfaces; -#if SERIES4 -using PepperDash.Essentials.AppServer; -#endif -namespace PepperDash.Essentials.Room.MobileControl -{ - public static class SetTopBoxControlsExtensions - { - public static void LinkActions(this ISetTopBoxControls dev, IMobileControl3 controller) - { - var prefix = string.Format(@"/device/{0}/", dev.Key); - - controller.AddAction(prefix + "dvrList", new PressAndHoldAction(dev.DvrList)); - controller.AddAction(prefix + "replay", new PressAndHoldAction(dev.Replay)); - } - - public static void UnlinkActions(this ISetTopBoxControls dev, IMobileControl3 controller) - { - var prefix = string.Format(@"/device/{0}/", dev.Key); - - controller.RemoveAction(prefix + "dvrList"); - controller.RemoveAction(prefix + "replay"); - } - } -} \ No newline at end of file diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/ISetTopBoxControlsMessenger.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/ISetTopBoxControlsMessenger.cs new file mode 100644 index 0000000..4927c33 --- /dev/null +++ b/4-series/mobile-control-messengers/DeviceTypeExtenstions/ISetTopBoxControlsMessenger.cs @@ -0,0 +1,25 @@ +using PepperDash.Core; +using PepperDash.Essentials.AppServer.Messengers; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +#if SERIES4 +#endif +namespace PepperDash.Essentials.Room.MobileControl +{ + public class ISetTopBoxControlsMessenger:MessengerBase + { + private readonly ISetTopBoxControls stbDevice; + public ISetTopBoxControlsMessenger(string key, string messagePath, IKeyName device) : base(key, messagePath, device) + { + stbDevice = device as ISetTopBoxControls; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/dvrList", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => stbDevice?.DvrList(b))); + AddAction("/replay", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => stbDevice?.Replay(b))); + } + } +} \ No newline at end of file diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/ITransportExtensions.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/ITransportExtensions.cs deleted file mode 100644 index ebf563e..0000000 --- a/4-series/mobile-control-messengers/DeviceTypeExtenstions/ITransportExtensions.cs +++ /dev/null @@ -1,39 +0,0 @@ -using PepperDash.Essentials.Core; -using PepperDash.Core; -using PepperDash.Essentials.Core.DeviceTypeInterfaces; -#if SERIES4 -using PepperDash.Essentials.AppServer; -#endif -namespace PepperDash.Essentials.Room.MobileControl -{ - public static class TransportExtensions - { - public static void LinkActions(this ITransport dev, IMobileControl3 controller) - { - var prefix = string.Format(@"/device/{0}/", ((IKeyed) dev).Key); - - controller.AddAction(prefix + "play", new PressAndHoldAction(dev.Play)); - controller.AddAction(prefix + "pause", new PressAndHoldAction(dev.Pause)); - controller.AddAction(prefix + "stop", new PressAndHoldAction(dev.Stop)); - controller.AddAction(prefix + "prevTrack", new PressAndHoldAction(dev.ChapPlus)); - controller.AddAction(prefix + "nextTrack", new PressAndHoldAction(dev.ChapMinus)); - controller.AddAction(prefix + "rewind", new PressAndHoldAction(dev.Rewind)); - controller.AddAction(prefix + "ffwd", new PressAndHoldAction(dev.FFwd)); - controller.AddAction(prefix + "record", new PressAndHoldAction(dev.Record)); - } - - public static void UnlinkActions(this ITransport dev, IMobileControl3 controller) - { - var prefix = string.Format(@"/device/{0}/", ((IKeyed) dev).Key); - - controller.RemoveAction(prefix + "play"); - controller.RemoveAction(prefix + "pause"); - controller.RemoveAction(prefix + "stop"); - controller.RemoveAction(prefix + "prevTrack"); - controller.RemoveAction(prefix + "nextTrack"); - controller.RemoveAction(prefix + "rewind"); - controller.RemoveAction(prefix + "ffwd"); - controller.RemoveAction(prefix + "record"); - } - } -} \ No newline at end of file diff --git a/4-series/mobile-control-messengers/DeviceTypeExtenstions/ITransportMessenger.cs b/4-series/mobile-control-messengers/DeviceTypeExtenstions/ITransportMessenger.cs new file mode 100644 index 0000000..c95f0eb --- /dev/null +++ b/4-series/mobile-control-messengers/DeviceTypeExtenstions/ITransportMessenger.cs @@ -0,0 +1,32 @@ +using PepperDash.Core; +using PepperDash.Essentials.AppServer.Messengers; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +#if SERIES4 +#endif +namespace PepperDash.Essentials.Room.MobileControl +{ + public class ITransportMessenger:MessengerBase + { + private readonly ITransport transportDevice; + public ITransportMessenger(string key, string messagePath, Device device) : base(key, messagePath, device) + { + transportDevice = device as ITransport; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/play", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => transportDevice?.Play(b))); + AddAction("/pause", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => transportDevice?.Pause(b))); + AddAction("/stop", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => transportDevice?.Stop(b))); + AddAction("/prevTrack", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => transportDevice?.ChapPlus(b))); + AddAction("/nextTrack", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => transportDevice?.ChapMinus(b))); + AddAction("/rewind", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => transportDevice?.Rewind(b))); + AddAction("/ffwd", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => transportDevice?.FFwd(b))); + AddAction("/record", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => transportDevice?.Record(b))); + } + + } +} \ No newline at end of file diff --git a/4-series/mobile-control-messengers/Messengers/CoreTwoWayDisplayBaseMessenger.cs b/4-series/mobile-control-messengers/Messengers/CoreTwoWayDisplayBaseMessenger.cs new file mode 100644 index 0000000..8bce8a4 --- /dev/null +++ b/4-series/mobile-control-messengers/Messengers/CoreTwoWayDisplayBaseMessenger.cs @@ -0,0 +1,91 @@ +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public class CoreTwoWayDisplayBaseMessenger : MessengerBase + { + private readonly TwoWayDisplayBase _display; + + public CoreTwoWayDisplayBaseMessenger(string key, string messagePath, Device display) + : base(key, messagePath, display) + { + _display = display as TwoWayDisplayBase; + } + + #region Overrides of MessengerBase + + public void SendFullStatus() + { + var messageObj = new TwoWayDisplayBaseStateMessage + { + //PowerState = _display.PowerIsOnFeedback.BoolValue, + CurrentInput = _display.CurrentInputFeedback.StringValue + }; + + PostStatusMessage(messageObj); + } + +#if SERIES4 + protected override void RegisterActions() +#else + protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) +#endif + { + base.RegisterActions(); + if (_display == null) + { + Debug.Console(0, this, $"Unable to register TwoWayDisplayBase messenger {Key}"); + return; + } + + AddAction("/fullStatus", (id, content) => SendFullStatus()); + + _display.PowerIsOnFeedback.OutputChange += PowerIsOnFeedbackOnOutputChange; + _display.CurrentInputFeedback.OutputChange += CurrentInputFeedbackOnOutputChange; + _display.IsCoolingDownFeedback.OutputChange += IsCoolingFeedbackOnOutputChange; + _display.IsWarmingUpFeedback.OutputChange += IsWarmingFeedbackOnOutputChange; + } + + private void CurrentInputFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) + { + PostStatusMessage(JToken.FromObject(new + { + currentInput = feedbackEventArgs.StringValue + })); + } + + + private void PowerIsOnFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) + { + PostStatusMessage(JToken.FromObject(new + { + powerState = feedbackEventArgs.BoolValue + }) + ); + } + + private void IsWarmingFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) + { + PostStatusMessage(JToken.FromObject(new + { + isWarming = feedbackEventArgs.BoolValue + }) + ); + + } + + private void IsCoolingFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) + { + PostStatusMessage(JToken.FromObject(new + { + isCooling = feedbackEventArgs.BoolValue + }) + ); + } + + #endregion + } +} diff --git a/4-series/mobile-control-messengers/Messengers/DeviceInfoMessenger.cs b/4-series/mobile-control-messengers/Messengers/DeviceInfoMessenger.cs new file mode 100644 index 0000000..8a17ce0 --- /dev/null +++ b/4-series/mobile-control-messengers/Messengers/DeviceInfoMessenger.cs @@ -0,0 +1,47 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using PepperDash.Essentials.Core.DeviceInfo; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public class DeviceInfoMessenger : MessengerBase + { + private readonly IDeviceInfoProvider _deviceInfoProvider; + public DeviceInfoMessenger(string key, string messagePath, IDeviceInfoProvider device) : base(key, messagePath, device as Device) + { + _deviceInfoProvider = device; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + _deviceInfoProvider.DeviceInfoChanged += (o, a) => + { + PostStatusMessage(JToken.FromObject(new + { + deviceInfo = a.DeviceInfo + })); + }; + + AddAction("/fullStatus", (id, context) => PostStatusMessage(new DeviceInfoStateMessage + { + DeviceInfo = _deviceInfoProvider.DeviceInfo + })); + + AddAction("/update", (id, context) => _deviceInfoProvider.UpdateDeviceInfo()); + } + } + + public class DeviceInfoStateMessage : DeviceStateMessageBase + { + [JsonProperty("deviceInfo")] + public DeviceInfo DeviceInfo { get; set; } + } +} diff --git a/4-series/mobile-control-messengers/Messengers/ICommunicationMonitorMessenger.cs b/4-series/mobile-control-messengers/Messengers/ICommunicationMonitorMessenger.cs new file mode 100644 index 0000000..7e4d03f --- /dev/null +++ b/4-series/mobile-control-messengers/Messengers/ICommunicationMonitorMessenger.cs @@ -0,0 +1,79 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public class ICommunicationMonitorMessenger : MessengerBase + { + private readonly ICommunicationMonitor _communicationMonitor; + + public ICommunicationMonitorMessenger(string key, string messagePath, ICommunicationMonitor device) : base(key, messagePath, device as IKeyName) + { + _communicationMonitor = device; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, content) => + { + PostStatusMessage(new CommunicationMonitorState + { + CommunicationMonitor = new CommunicationMonitorProps + { + IsOnline = _communicationMonitor.CommunicationMonitor.IsOnline, + Status = _communicationMonitor.CommunicationMonitor.Status + } + }); + }); + + _communicationMonitor.CommunicationMonitor.StatusChange += (sender, args) => + { + PostStatusMessage(JToken.FromObject(new + { + commMonitor = new CommunicationMonitorProps + { + IsOnline = _communicationMonitor.CommunicationMonitor.IsOnline, + Status = _communicationMonitor.CommunicationMonitor.Status + } + })); + }; + } + } + + /// + /// Represents the state of the communication monitor + /// + public class CommunicationMonitorState : DeviceStateMessageBase + { + [JsonProperty("commMonitor", NullValueHandling = NullValueHandling.Ignore)] + public CommunicationMonitorProps CommunicationMonitor { get; set; } + + } + + public class CommunicationMonitorProps + { /// + /// For devices that implement ICommunicationMonitor, reports the online status of the device + /// + [JsonProperty("isOnline", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsOnline { get; set; } + + /// + /// For devices that implement ICommunicationMonitor, reports the online status of the device + /// + [JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)] + [JsonConverter(typeof(StringEnumConverter))] + public MonitorStatus Status { get; set; } + + } + +} diff --git a/4-series/mobile-control-messengers/Messengers/IHasCurrentSourceInfoMessenger.cs b/4-series/mobile-control-messengers/Messengers/IHasCurrentSourceInfoMessenger.cs new file mode 100644 index 0000000..40a80a7 --- /dev/null +++ b/4-series/mobile-control-messengers/Messengers/IHasCurrentSourceInfoMessenger.cs @@ -0,0 +1,61 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public class IHasCurrentSourceInfoMessenger : MessengerBase + { + private readonly IHasCurrentSourceInfoChange sourceDevice; + public IHasCurrentSourceInfoMessenger(string key, string messagePath, IHasCurrentSourceInfoChange device) : base(key, messagePath, device as IKeyName) + { + sourceDevice = device; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, content) => + { + var message = new CurrentSourceStateMessage + { + CurrentSourceKey = sourceDevice.CurrentSourceInfoKey, + CurrentSource = sourceDevice.CurrentSourceInfo + }; + + PostStatusMessage(message); + }); + + sourceDevice.CurrentSourceChange += (sender, e) => { + switch (e) + { + case ChangeType.DidChange: + { + PostStatusMessage(JToken.FromObject(new + { + currentSourceKey = string.IsNullOrEmpty(sourceDevice.CurrentSourceInfoKey) ? string.Empty : sourceDevice.CurrentSourceInfoKey, + currentSource = sourceDevice.CurrentSourceInfo + })); + break; + } + } + }; + } + } + + public class CurrentSourceStateMessage: DeviceStateMessageBase + { + [JsonProperty("currentSourceKey", NullValueHandling = NullValueHandling.Ignore)] + public string CurrentSourceKey { get; set; } + + [JsonProperty("currentSource")] + public SourceListItem CurrentSource { get; set; } + } +} diff --git a/4-series/mobile-control-messengers/Messengers/IHasPowerControlWithFeedbackMessenger.cs b/4-series/mobile-control-messengers/Messengers/IHasPowerControlWithFeedbackMessenger.cs new file mode 100644 index 0000000..bf838e9 --- /dev/null +++ b/4-series/mobile-control-messengers/Messengers/IHasPowerControlWithFeedbackMessenger.cs @@ -0,0 +1,57 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Essentials.Core; +using PepperDash.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public class IHasPowerControlWithFeedbackMessenger: MessengerBase + { + private readonly IHasPowerControlWithFeedback _powerControl; + + public IHasPowerControlWithFeedbackMessenger(string key, string messagePath, IHasPowerControlWithFeedback powerControl) + : base(key, messagePath, powerControl as Device) + { + _powerControl = powerControl; + } + + public void SendFullStatus() + { + var messageObj = new PowerControlWithFeedbackStateMessage + { + PowerState = _powerControl.PowerIsOnFeedback.BoolValue + }; + + PostStatusMessage(messageObj); + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, content) => SendFullStatus()); + + _powerControl.PowerIsOnFeedback.OutputChange += PowerIsOnFeedback_OutputChange; ; + } + + private void PowerIsOnFeedback_OutputChange(object sender, FeedbackEventArgs args) + { + PostStatusMessage(JToken.FromObject(new + { + powerState = args.BoolValue + }) + ); + } + } + + public class PowerControlWithFeedbackStateMessage : DeviceStateMessageBase + { + [JsonProperty("powerState", NullValueHandling = NullValueHandling.Ignore)] + public bool? PowerState { get; set; } + } +} diff --git a/4-series/mobile-control-messengers/Messengers/ILevelControlsMessenger.cs b/4-series/mobile-control-messengers/Messengers/ILevelControlsMessenger.cs new file mode 100644 index 0000000..f8081ee --- /dev/null +++ b/4-series/mobile-control-messengers/Messengers/ILevelControlsMessenger.cs @@ -0,0 +1,95 @@ +using Independentsoft.Exchange; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public class ILevelControlsMessenger : MessengerBase + { + private ILevelControls levelControlsDevice; + public ILevelControlsMessenger(string key, string messagePath, ILevelControls device) : base(key, messagePath, device as Device) + { + levelControlsDevice = device; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, context) => + { + var message = new LevelControlStateMessage + { + Levels = levelControlsDevice.LevelControlPoints.ToDictionary(kv => kv.Key, kv => new Volume { Level = kv.Value.VolumeLevelFeedback.IntValue, Muted = kv.Value.MuteFeedback.BoolValue }) + }; + + PostStatusMessage(message); + }); + + foreach(var levelControl in levelControlsDevice.LevelControlPoints) + { + // reassigning here just in case of lambda closure issues + var key = levelControl.Key; + var control = levelControl.Value; + + AddAction($"/{key}/level", (id, content) => + { + var request = content.ToObject>(); + + control.SetVolume(request.Value); + }); + + AddAction($"/{key}/muteToggle", (id, content) => + { + control.MuteToggle(); + }); + + AddAction($"/{key}/muteOn", (id, content) => control.MuteOn()); + + AddAction($"/{key}/muteOff", (id, content) => control.MuteOff()); + + AddAction($"/{key}/volumeUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => control.VolumeUp(b))); + + AddAction($"/{key}/volumeDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(content, (b) => control.VolumeDown(b))); + + control.VolumeLevelFeedback.OutputChange += (o, a) => PostStatusMessage(JToken.FromObject(new + { + levelControls = new Dictionary + { + {key, new Volume{Level = a.IntValue} } + } + })); + + control.MuteFeedback.OutputChange += (o, a) => PostStatusMessage(JToken.FromObject(new + { + levelControls = new Dictionary + { + {key, new Volume{Muted = a.BoolValue} } + } + })); + } + } + } + + public class LevelControlStateMessage:DeviceStateMessageBase + { + [JsonProperty("levelControls")] + public Dictionary Levels { get; set; } + } + + public class LevelControlRequestMessage + { + [JsonProperty("key")] + public string Key { get; set; } + + [JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)] + public ushort? Level { get; set; } + } +} diff --git a/4-series/mobile-control-messengers/Messengers/IMatrixRoutingMessenger.cs b/4-series/mobile-control-messengers/Messengers/IMatrixRoutingMessenger.cs new file mode 100644 index 0000000..ba5ee55 --- /dev/null +++ b/4-series/mobile-control-messengers/Messengers/IMatrixRoutingMessenger.cs @@ -0,0 +1,168 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Routing; +using System.Collections.Generic; +using System.Linq; +using Serilog.Events; +using System; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + /// + /// Messenger for devices that implment IMatrixRouting + /// + public class IMatrixRoutingMessenger: MessengerBase + { + private readonly IMatrixRouting matrixDevice; + public IMatrixRoutingMessenger(string key, string messagePath, IMatrixRouting device) : base(key, messagePath, device as Device) + { + matrixDevice = device; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, content) => + { + try + { + Debug.LogMessage(LogEventLevel.Verbose, "InputCount: {inputCount}, OutputCount: {outputCount}", this, matrixDevice.InputSlots.Count, matrixDevice.OutputSlots.Count); + var message = new MatrixStateMessage + { + Outputs = matrixDevice.OutputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingOutput(kvp.Value)), + Inputs = matrixDevice.InputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingInput(kvp.Value)), + }; + + + PostStatusMessage(message); + } + catch (Exception e) + { + Debug.LogMessage(e, "Exception Getting full status: {@exception}", this, e); + } + }); + + AddAction("/route", (id, content) => + { + var request = content.ToObject(); + + matrixDevice.Route(request.InputKey, request.OutputKey, request.RouteType); + }); + + foreach(var output in matrixDevice.OutputSlots) + { + var key = output.Key; + var outputSlot = output.Value; + + outputSlot.OutputSlotChanged += (sender, args) => + { + PostStatusMessage(JToken.FromObject(new + { + outputs = matrixDevice.OutputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingOutput(kvp.Value)) + })); + }; + } + + foreach(var input in matrixDevice.InputSlots) + { + var key = input.Key; + var inputSlot = input.Value; + + inputSlot.VideoSyncChanged += (sender, args) => + { + PostStatusMessage(JToken.FromObject(new + { + inputs = matrixDevice.InputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingInput(kvp.Value)) + })); + }; + } + } + } + + public class MatrixStateMessage : DeviceStateMessageBase + { + [JsonProperty("outputs")] + public Dictionary Outputs; + + [JsonProperty("inputs")] + public Dictionary Inputs; + } + + public class RoutingInput + { + private IRoutingInputSlot _input; + + [JsonProperty("txDeviceKey", NullValueHandling = NullValueHandling.Ignore)] + public string TxDeviceKey => _input?.TxDeviceKey; + + [JsonProperty("slotNumber", NullValueHandling = NullValueHandling.Ignore)] + public int? SlotNumber => _input?.SlotNumber; + + [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + [JsonProperty("supportedSignalTypes", NullValueHandling = NullValueHandling.Ignore)] + public eRoutingSignalType? SupportedSignalTypes => _input?.SupportedSignalTypes; + + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + public string Name => _input?.Name; + + [JsonProperty("isOnline", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsOnline => _input?.IsOnline.BoolValue; + + [JsonProperty("videoSyncDetected", NullValueHandling = NullValueHandling.Ignore)] + + public bool? VideoSyncDetected => _input?.VideoSyncDetected; + + [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] + public string Key => _input?.Key; + + public RoutingInput(IRoutingInputSlot input) + { + _input = input; + } + } + + public class RoutingOutput + { + private IRoutingOutputSlot _output; + + + public RoutingOutput(IRoutingOutputSlot output) + { + _output = output; + } + + [JsonProperty("rxDeviceKey")] + public string RxDeviceKey => _output.RxDeviceKey; + + [JsonProperty("currentRoutes")] + public Dictionary CurrentRoutes => _output.CurrentRoutes.ToDictionary(kvp => kvp.Key.ToString(), kvp => new RoutingInput(kvp.Value)); + + [JsonProperty("slotNumber")] + public int SlotNumber => _output.SlotNumber; + + [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + [JsonProperty("supportedSignalTypes")] + public eRoutingSignalType SupportedSignalTypes => _output.SupportedSignalTypes; + + [JsonProperty("name")] + public string Name => _output.Name; + + [JsonProperty("key")] + public string Key => _output.Key; + } + + public class MatrixRouteRequest + { + [JsonProperty("outputKey")] + public string OutputKey { get; set; } + + [JsonProperty("inputKey")] + public string InputKey { get; set; } + + [JsonProperty("routeType")] + public eRoutingSignalType RouteType { get; set; } + } +} diff --git a/4-series/mobile-control-messengers/Messengers/ISelectableItemsMessenger.cs b/4-series/mobile-control-messengers/Messengers/ISelectableItemsMessenger.cs new file mode 100644 index 0000000..fe7ba9c --- /dev/null +++ b/4-series/mobile-control-messengers/Messengers/ISelectableItemsMessenger.cs @@ -0,0 +1,63 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public class ISelectableItemsMessenger : MessengerBase + { + private ISelectableItems itemDevice; + + private readonly string _propName; + public ISelectableItemsMessenger(string key, string messagePath, ISelectableItems device, string propName) : base(key, messagePath, device as Device) + { + itemDevice = device; + _propName = propName; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, context) => + { + SendFullStatus(); + }); + + itemDevice.ItemsUpdated += (sender, args) => + { + SendFullStatus(); + }; + + foreach (var input in itemDevice.Items) + { + var key = input.Key; + var localItem = input.Value; + + AddAction($"/{localItem.Key}", (id, content) => + { + localItem.Select(); + }); + + localItem.ItemUpdated += (sender, args) => + { + SendFullStatus(); + }; + } + } + + private void SendFullStatus() + { + var stateObject = new JObject(); + stateObject[_propName] = JToken.FromObject(itemDevice); + PostStatusMessage(stateObject); + } + } + +} diff --git a/4-series/mobile-control-messengers/Messengers/IShutdownPromptTimerMessenger.cs b/4-series/mobile-control-messengers/Messengers/IShutdownPromptTimerMessenger.cs new file mode 100644 index 0000000..b17ba7c --- /dev/null +++ b/4-series/mobile-control-messengers/Messengers/IShutdownPromptTimerMessenger.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public class IShutdownPromptTimerMessenger : MessengerBase + { + private readonly IShutdownPromptTimer _room; + + public IShutdownPromptTimerMessenger(string key, string messagePath, IShutdownPromptTimer room) + : base(key, messagePath, room as Device) + { + _room = room; + } + + protected override void RegisterActions() + { + AddAction("/status", (id, content) => + { + SendFullStatus(); + }); + + AddAction("/setShutdownPromptSeconds", (id, content) => + { + var response = content.ToObject(); + + _room.SetShutdownPromptSeconds(response); + + SendFullStatus(); + }); + + AddAction("/shutdownStart", (id, content) => _room.StartShutdown(eShutdownType.Manual)); + + AddAction("/shutdownEnd", (id, content) => _room.ShutdownPromptTimer.Finish()); + + AddAction("/shutdownCancel", (id, content) => _room.ShutdownPromptTimer.Cancel()); + + + _room.ShutdownPromptTimer.HasStarted += (sender, args) => + { + PostEventMessage("timerStarted"); + }; + + _room.ShutdownPromptTimer.HasFinished += (sender, args) => + { + + PostEventMessage("timerFinished"); + }; + + _room.ShutdownPromptTimer.WasCancelled += (sender, args) => + { + PostEventMessage("timerCancelled"); + }; + + _room.ShutdownPromptTimer.SecondsRemainingFeedback.OutputChange += (sender, args) => + { + var status = new + { + secondsRemaining = _room.ShutdownPromptTimer.SecondsRemainingFeedback.IntValue, + percentageRemaining = _room.ShutdownPromptTimer.PercentFeedback.UShortValue + }; + + PostStatusMessage(JToken.FromObject(status)); + }; + } + + private void SendFullStatus() + { + var status = new IShutdownPromptTimerStateMessage + { + ShutdownPromptSeconds = _room.ShutdownPromptTimer.SecondsToCount, + SecondsRemaining = _room.ShutdownPromptTimer.SecondsRemainingFeedback.IntValue, + PercentageRemaining = _room.ShutdownPromptTimer.PercentFeedback.UShortValue + }; + + PostStatusMessage(status); + } + } + + + public class IShutdownPromptTimerStateMessage : DeviceStateMessageBase + { + [JsonProperty("secondsRemaining")] + public int SecondsRemaining { get; set; } + + [JsonProperty("percentageRemaining")] + public int PercentageRemaining { get; set; } + + [JsonProperty("shutdownPromptSeconds")] + public int ShutdownPromptSeconds { get; set; } + } +} diff --git a/4-series/mobile-control-messengers/Messengers/ISwitchedOutputMessenger.cs b/4-series/mobile-control-messengers/Messengers/ISwitchedOutputMessenger.cs new file mode 100644 index 0000000..6d3bceb --- /dev/null +++ b/4-series/mobile-control-messengers/Messengers/ISwitchedOutputMessenger.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PepperDash.Essentials.Core.CrestronIO; +using PepperDash.Essentials.Core.Shades; +using Newtonsoft.Json; +using PepperDash.Core; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public class ISwitchedOutputMessenger : MessengerBase + { + + private readonly ISwitchedOutput device; + + public ISwitchedOutputMessenger(string key, ISwitchedOutput device, string messagePath) + : base(key, messagePath, device as Device) + { + this.device = device; + } + +#if SERIES4 + protected override void RegisterActions() +#else + protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) +#endif + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, content) => SendFullStatus()); + + AddAction("/on", (id, content) => + { + + device.On(); + + }); + + AddAction("/off", (id, content) => + { + + device.Off(); + + }); + + device.OutputIsOnFeedback.OutputChange += new EventHandler((o, a) => SendFullStatus()); + } + + private void SendFullStatus() + { + var state = new ISwitchedOutputStateMessage + { + IsOn = device.OutputIsOnFeedback.BoolValue + }; + + PostStatusMessage(state); + } + } + + public class ISwitchedOutputStateMessage : DeviceStateMessageBase + { + [JsonProperty("isOn")] + public bool IsOn { get; set; } + } +} diff --git a/4-series/mobile-control-messengers/Messengers/ITechPasswordMessenger.cs b/4-series/mobile-control-messengers/Messengers/ITechPasswordMessenger.cs new file mode 100644 index 0000000..46e2a5a --- /dev/null +++ b/4-series/mobile-control-messengers/Messengers/ITechPasswordMessenger.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Independentsoft.Json.Parser; +using Newtonsoft.Json; +using PepperDash.Core; +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public class ITechPasswordMessenger : MessengerBase + { + private readonly ITechPassword _room; + + public ITechPasswordMessenger(string key, string messagePath, ITechPassword room) + : base(key, messagePath, room as Device) + { + _room = room; + } + + protected override void RegisterActions() + { + + AddAction("/status", (id, content) => + { + SendFullStatus(); + }); + + AddAction("/validateTechPassword", (id, content) => + { + var password = content.Value("password"); + + _room.ValidateTechPassword(password); + }); + + AddAction("/setTechPassword", (id, content) => + { + var response = content.ToObject(); + + _room.SetTechPassword(response.OldPassword, response.NewPassword); + }); + + _room.TechPasswordChanged += (sender, args) => + { + PostEventMessage("passwordChangedSuccessfully"); + }; + + _room.TechPasswordValidateResult += (sender, args) => + { + var evt = new ITechPasswordEventMessage + { + IsValid = args.IsValid + }; + + PostEventMessage(evt, "passwordValidationResult"); + }; + } + + private void SendFullStatus() + { + var status = new ITechPasswordStateMessage + { + TechPasswordLength = _room.TechPasswordLength + }; + + PostStatusMessage(status); + } + + } + + public class ITechPasswordStateMessage : DeviceStateMessageBase + { + [JsonProperty("techPasswordLength", NullValueHandling = NullValueHandling.Ignore)] + public int? TechPasswordLength { get; set; } + } + + public class ITechPasswordEventMessage : DeviceEventMessageBase + { + [JsonProperty("isValid", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsValid { get; set; } + } + + class SetTechPasswordContent + { + [JsonProperty("oldPassword")] + public string OldPassword { get; set; } + + [JsonProperty("newPassword")] + public string NewPassword { get; set; } + } + +} diff --git a/4-series/mobile-control-messengers/Messengers/PressAndHoldHandler.cs b/4-series/mobile-control-messengers/Messengers/PressAndHoldHandler.cs new file mode 100644 index 0000000..44c51ab --- /dev/null +++ b/4-series/mobile-control-messengers/Messengers/PressAndHoldHandler.cs @@ -0,0 +1,96 @@ +using Crestron.SimplSharp; +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using System; +using System.Collections.Generic; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public static class PressAndHoldHandler + { + private const long ButtonHeartbeatInterval = 1000; + + private static readonly Dictionary _pushedActions = new Dictionary(); + + private static readonly Dictionary>> _pushedActionHandlers; + + static PressAndHoldHandler() + { + _pushedActionHandlers = new Dictionary>> + { + {"pressed", AddTimer }, + {"held", ResetTimer }, + {"released", StopTimer } + }; + } + + private static void AddTimer(string type, Action action) + { + + if (_pushedActions.TryGetValue(type, out CTimer cancelTimer)) + { + return; + } + + cancelTimer = new CTimer(o => + { + action(false); + + _pushedActions.Remove(type); + }, ButtonHeartbeatInterval); + + _pushedActions.Add(type, cancelTimer); + } + + private static void ResetTimer(string type, Action action) + { + + if (!_pushedActions.TryGetValue(type, out CTimer cancelTimer)) { return; } + + cancelTimer.Reset(ButtonHeartbeatInterval); + } + + private static void StopTimer(string type, Action action) + { + + if (!_pushedActions.TryGetValue(type, out CTimer cancelTimer)) { return; } + + action(false); + cancelTimer.Stop(); + _pushedActions.Remove(type); + } + + public static Action> GetPressAndHoldHandler(string value) + { + + if (!_pushedActionHandlers.TryGetValue(value, out Action> handler)) + { + Debug.Console(0, "Unable to get Press & Hold handler for {0}", value); + return null; + } + + return handler; + } + + public static void HandlePressAndHold(JToken content, Action action) + { + var msg = content.ToObject>(); + + Debug.Console(2, "HandlePressAndHold msg: {0}", msg.Value); + + + var timerHandler = GetPressAndHoldHandler(msg.Value); + if (timerHandler == null) + { + return; + } + + timerHandler(msg.Value, action); + + if (msg.Value.Equals("pressed", StringComparison.InvariantCultureIgnoreCase)) + action(true); + else if (msg.Value.Equals("released", StringComparison.InvariantCultureIgnoreCase)) + action(false); + } + } +} diff --git a/4-series/mobile-control-messengers/MobileControlMessage.cs b/4-series/mobile-control-messengers/MobileControlMessage.cs new file mode 100644 index 0000000..5e284df --- /dev/null +++ b/4-series/mobile-control-messengers/MobileControlMessage.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + +#if SERIES4 + public class MobileControlMessage : IMobileControlMessage +#else + public class MobileControlMessage +#endif + { + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("clientId")] + public string ClientId { get; set; } + + [JsonProperty("content")] + public JToken Content { get; set; } + } +} diff --git a/4-series/mobile-control-messengers/MobileControlSimpleContent.cs b/4-series/mobile-control-messengers/MobileControlSimpleContent.cs new file mode 100644 index 0000000..1d80475 --- /dev/null +++ b/4-series/mobile-control-messengers/MobileControlSimpleContent.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace PepperDash.Essentials.AppServer +{ + public class MobileControlSimpleContent + { + [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] + public T Value { get; set; } + } +} diff --git a/4-series/mobile-control-messengers/Properties/AssemblyInfo.cs b/4-series/mobile-control-messengers/Properties/AssemblyInfo.cs index 7afd4db..2d559a0 100644 --- a/4-series/mobile-control-messengers/Properties/AssemblyInfo.cs +++ b/4-series/mobile-control-messengers/Properties/AssemblyInfo.cs @@ -1,6 +1,4 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from diff --git a/4-series/mobile-control-messengers/mobile-control-messengers.csproj b/4-series/mobile-control-messengers/mobile-control-messengers.csproj index 22e3dcf..986b110 100644 --- a/4-series/mobile-control-messengers/mobile-control-messengers.csproj +++ b/4-series/mobile-control-messengers/mobile-control-messengers.csproj @@ -28,7 +28,6 @@ - @@ -36,7 +35,6 @@ - @@ -48,7 +46,7 @@ - + @@ -60,10 +58,9 @@ - - + \ No newline at end of file