From 3daceed4f1d767836cc0c146a7705dfb47b21d6a Mon Sep 17 00:00:00 2001 From: Luc FASQUELLE Date: Fri, 16 Aug 2024 17:06:15 +0200 Subject: [PATCH] =?UTF-8?q?.Net=206.0=20=F0=9F=9A=80=20(#149)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR is a simply convert to .Net 6 and update dependencies. It should be fix issue #127 Next should be : use .Net 5 and 6 news features (likes records) + see issue #147. --- .github/dependabot.yml | 2 +- .github/workflows/ci.yml | 12 +- .gitignore | 450 +++--------------- .idea/.gitignore | 13 + .idea/.idea.Netatmo/.idea/.gitignore | 13 + .idea/.idea.Netatmo/.idea/.name | 1 + .../.idea/codeStyles/Project.xml | 23 + .../.idea/codeStyles/codeStyleConfig.xml | 5 + .idea/.idea.Netatmo/.idea/encodings.xml | 4 + .idea/.idea.Netatmo/.idea/indexLayout.xml | 8 + .idea/.idea.Netatmo/.idea/vcs.xml | 7 + .idea/indexLayout.xml | 8 + .idea/vcs.xml | 6 + Netatmo.sln | 34 ++ Netatmo.sln.DotSettings | 312 ++++++++++++ src/.gitignore | 12 - src/Netatmo.Tests/AirClient.cs | 56 --- .../GetRoomMeasureArgumentExceptionData.cs | 63 --- src/Netatmo.Tests/CredentialManager.cs | 112 ----- src/Netatmo.Tests/EnergyClient.cs | 302 ------------ src/Netatmo.Tests/WeatherClient.cs | 63 --- src/Netatmo.sln | 28 -- src/Netatmo/AirClient.cs | 45 +- src/Netatmo/Client.cs | 54 +-- src/Netatmo/Configuration.cs | 30 +- .../StringToDateTimeZoneConverter.cs | 22 +- .../Converters/TimestampToInstantConverter.cs | 26 +- src/Netatmo/CredentialManager.cs | 107 ++--- src/Netatmo/EnergyClient.cs | 330 +++++++------ src/Netatmo/Enums/BatteryLevelEnum.cs | 21 +- src/Netatmo/Enums/FeelLikeAlgoEnum.cs | 11 +- src/Netatmo/Enums/PressureUnitEnum.cs | 13 +- src/Netatmo/Enums/RfStrengthEnum.cs | 17 +- src/Netatmo/Enums/UnitEnum.cs | 11 +- src/Netatmo/Enums/WifiStrengthEnum.cs | 15 +- src/Netatmo/Enums/WindUnitEnum.cs | 17 +- src/Netatmo/IAirClient.cs | 10 +- src/Netatmo/IClient.cs | 21 +- src/Netatmo/ICredentialManager.cs | 20 +- src/Netatmo/IEnergyClient.cs | 28 +- src/Netatmo/IWeatherClient.cs | 10 +- .../Models/Client/Air/GetHomeCoachsData.cs | 15 +- .../Client/Air/GetHomeCoachsDataRequest.cs | 9 +- .../Client/Air/HomesCoachs/DashBoardData.cs | 55 ++- .../Models/Client/Air/HomesCoachs/Devices.cs | 87 ++-- .../Client/Air/HomesCoachs/HealthIdx.cs | 17 +- src/Netatmo/Models/Client/DataResponse.cs | 24 +- .../Energy/CreateHomeScheduleRequest.cs | 62 ++- .../Energy/CreateHomeScheduleResponse.cs | 13 +- .../Energy/DeleteHomeScheduleRequest.cs | 15 +- .../Client/Energy/Enums/ZoneTypeEnum.cs | 21 +- .../Models/Client/Energy/GetHomeStatusBody.cs | 11 +- .../Client/Energy/GetHomeStatusRequest.cs | 15 +- .../Models/Client/Energy/GetHomesDataBody.cs | 15 +- .../Client/Energy/GetHomesDataRequest.cs | 15 +- .../Client/Energy/GetRoomMeasureParameters.cs | 25 +- .../Client/Energy/GetRoomMeasureRequest.cs | 43 +- .../Models/Client/Energy/HomeStatus/Home.cs | 19 +- .../Models/Client/Energy/HomeStatus/Module.cs | 155 +++--- .../Models/Client/Energy/HomeStatus/Room.cs | 47 +- .../Models/Client/Energy/HomesData/Home.cs | 51 +- .../Models/Client/Energy/HomesData/Module.cs | 37 +- .../Models/Client/Energy/HomesData/Room.cs | 31 +- .../Client/Energy/HomesData/Schedule.cs | 43 +- .../Models/Client/Energy/HomesData/User.cs | 39 +- .../Models/Client/Energy/HomesData/Zone.cs | 23 +- .../Energy/RenameHomeScheduleRequest.cs | 19 +- .../Energy/RoomMeasure/DateTemperatureStep.cs | 7 +- .../Models/Client/Energy/RoomMeasure/IStep.cs | 7 +- .../Models/Client/Energy/RoomMeasure/Step.cs | 19 +- .../Energy/RoomMeasure/TemperatureStep.cs | 7 +- .../Client/Energy/SetRoomThermpointRequest.cs | 27 +- .../Client/Energy/SetThermModeRequest.cs | 19 +- .../Energy/SwitchHomeScheduleRequest.cs | 15 +- .../Client/Energy/SyncHomeScheduleRequest.cs | 84 ++-- src/Netatmo/Models/Client/Energy/Timetable.cs | 31 +- src/Netatmo/Models/Client/Energy/Zone.cs | 72 ++- src/Netatmo/Models/Client/Place.cs | 28 +- src/Netatmo/Models/Client/Token.cs | 18 +- src/Netatmo/Models/Client/User.cs | 12 +- .../Client/Weather/GetStationsDataBody.cs | 15 +- .../Client/Weather/GetStationsDataRequest.cs | 15 +- .../Weather/StationsData/Administrative.cs | 35 +- .../DashboardData/BaseStationDashBoardData.cs | 61 ++- .../DashboardData/DashBoardData.cs | 11 +- .../DashboardData/ICO2DashBoardData.cs | 11 +- .../DashboardData/IDashBoardData.cs | 11 +- .../DashboardData/IGustDashBoardData.cs | 15 +- .../DashboardData/IHumidityDashBoardData.cs | 11 +- .../DashboardData/INoiseDashBoardData.cs | 11 +- .../DashboardData/IPressureDashBoardData.cs | 21 +- .../DashboardData/IRainDashBoardData.cs | 19 +- .../ITemperatureDashBoardData.cs | 33 +- .../DashboardData/IWindDashBoardData.cs | 23 +- .../DashboardData/IndoorDashBoardData.cs | 41 +- .../DashboardData/OutdoorDashBoardData.cs | 37 +- .../DashboardData/RainGaugeDashBoardData.cs | 19 +- .../DashboardData/WindGaugeDashBoardData.cs | 27 +- .../DashboardData/WindHistoric.cs | 19 +- .../Client/Weather/StationsData/Device.cs | 85 ++-- .../Client/Weather/StationsData/Module.cs | 232 +++++---- src/Netatmo/Models/CredentialToken.cs | 26 +- src/Netatmo/Netatmo.csproj | 8 +- src/Netatmo/Scale.cs | 99 ++-- src/Netatmo/Scope.cs | 103 ++-- src/Netatmo/ThermostatMeasurementType.cs | 105 ++-- src/Netatmo/WeatherClient.cs | 46 +- src/TestApp/Program.cs | 94 ---- tests/Netatmo.Tests/AirClient.cs | 49 ++ .../GetRoomMeasureArgumentExceptionData.cs | 60 +++ tests/Netatmo.Tests/CredentialManager.cs | 112 +++++ tests/Netatmo.Tests/EnergyClient.cs | 264 ++++++++++ .../Netatmo.Tests/Netatmo.Tests.csproj | 26 +- tests/Netatmo.Tests/WeatherClient.cs | 58 +++ tests/TestApp/Program.cs | 89 ++++ {src => tests}/TestApp/TestApp.csproj | 7 +- 116 files changed, 2661 insertions(+), 2831 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/.idea.Netatmo/.idea/.gitignore create mode 100644 .idea/.idea.Netatmo/.idea/.name create mode 100644 .idea/.idea.Netatmo/.idea/codeStyles/Project.xml create mode 100644 .idea/.idea.Netatmo/.idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/.idea.Netatmo/.idea/encodings.xml create mode 100644 .idea/.idea.Netatmo/.idea/indexLayout.xml create mode 100644 .idea/.idea.Netatmo/.idea/vcs.xml create mode 100644 .idea/indexLayout.xml create mode 100644 .idea/vcs.xml create mode 100644 Netatmo.sln create mode 100644 Netatmo.sln.DotSettings delete mode 100644 src/.gitignore delete mode 100644 src/Netatmo.Tests/AirClient.cs delete mode 100644 src/Netatmo.Tests/ClassData/Energy/GetRoomMeasureArgumentExceptionData.cs delete mode 100644 src/Netatmo.Tests/CredentialManager.cs delete mode 100644 src/Netatmo.Tests/EnergyClient.cs delete mode 100644 src/Netatmo.Tests/WeatherClient.cs delete mode 100644 src/Netatmo.sln delete mode 100644 src/TestApp/Program.cs create mode 100644 tests/Netatmo.Tests/AirClient.cs create mode 100644 tests/Netatmo.Tests/ClassData/Energy/GetRoomMeasureArgumentExceptionData.cs create mode 100644 tests/Netatmo.Tests/CredentialManager.cs create mode 100644 tests/Netatmo.Tests/EnergyClient.cs rename {src => tests}/Netatmo.Tests/Netatmo.Tests.csproj (53%) create mode 100644 tests/Netatmo.Tests/WeatherClient.cs create mode 100644 tests/TestApp/Program.cs rename {src => tests}/TestApp/TestApp.csproj (70%) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index cc84a12..1e2dd8b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -15,4 +15,4 @@ updates: reviewers: - 'riges' assignees: - - 'riges' \ No newline at end of file + - 'riges' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 937a5cf..ebca76d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,11 +25,11 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: 5.0.x + dotnet-version: 6.0.x - name: Restore packages - run: dotnet restore src + run: dotnet restore - name: Test - run: dotnet test src --configuration Release + run: dotnet test --configuration Release build: name: Create Package nuget needs: test @@ -47,11 +47,11 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: 5.0.x + dotnet-version: 6.0.x - name: Restore packages - run: dotnet restore src + run: dotnet restore - name: Build and create package nuget - run: dotnet pack src -c Release -p:PackageVersion=${{steps.vars.outputs.tag}} + run: dotnet pack -c Release -p:PackageVersion=${{steps.vars.outputs.tag}} - name: Publish artifact uses: actions/upload-artifact@master with: diff --git a/.gitignore b/.gitignore index fab04a0..3fa9241 100644 --- a/.gitignore +++ b/.gitignore @@ -1,395 +1,55 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - -# User-specific files -*.rsuser -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Mono auto generated files -mono_crash.* - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUnit -*.VisualState.xml -TestResult.xml -nunit-*.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_h.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*_wpftmp.csproj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# NuGet Symbol Packages -*.snupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx -*.appxbundle -*.appxupload - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!?*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser -*- [Bb]ackup.rdl -*- [Bb]ackup ([0-9]).rdl -*- [Bb]ackup ([0-9][0-9]).rdl - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# CodeRush personal settings -.cr/personal - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ - -# Local History for Visual Studio -.localhistory/ - -# BeatPulse healthcheck temp database -healthchecksdb - -# Backup folder for Package Reference Convert tool in Visual Studio 2017 -MigrationBackup/ - -# Ionide (cross platform F# VS Code tools) working folder -.ionide/ - -# We chose to totally ignore .idea folders -.idea/ - -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json - -# Common IntelliJ Platform excludes - -# User specific -**/.idea/**/workspace.xml -**/.idea/**/tasks.xml -**/.idea/shelf/* -**/.idea/dictionaries - -# Sensitive or high-churn files -**/.idea/**/dataSources/ -**/.idea/**/dataSources.ids -**/.idea/**/dataSources.xml -**/.idea/**/dataSources.local.xml -**/.idea/**/sqlDataSources.xml -**/.idea/**/dynamic.xml - -# Rider -# Rider auto-generates .iml files, and contentModel.xml -**/.idea/**/*.iml -**/.idea/**/contentModel.xml -**/.idea/**/modules.xml - -*.suo -*.user -.vs/ -[Bb]in/ -[Oo]bj/ -_UpgradeReport_Files/ -[Pp]ackages/ - -Thumbs.db -Desktop.ini -.DS_Store +# Netatmo +.env + +## +## Visual Studio Code +## +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +## +## Visual Studio Code - Ionide extention +## +.ionide/ + +# terraform +.terraform +*.tfstate.d + +# Common IntelliJ Platform excludes + +# User specific +**/.idea/**/workspace.xml +**/.idea/**/tasks.xml +**/.idea/shelf/* +**/.idea/dictionaries +**/.idea/httpRequests/ + +# Sensitive or high-churn files +**/.idea/**/dataSources/ +**/.idea/**/dataSources.ids +**/.idea/**/dataSources.xml +**/.idea/**/dataSources.local.xml +**/.idea/**/sqlDataSources.xml +**/.idea/**/dynamic.xml + +# Rider +# Rider auto-generates .iml files, and contentModel.xml +**/.idea/**/*.iml +**/.idea/**/contentModel.xml +**/.idea/**/modules.xml + +*.suo +*.user +.vs/ +[Bb]in/ +[Oo]bj/ +_UpgradeReport_Files/ +[Pp]ackages/ + +Thumbs.db +Desktop.ini +.DS_Store diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..cd5844f --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/projectSettingsUpdater.xml +/.idea.Netatmo.iml +/contentModel.xml +/modules.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.Netatmo/.idea/.gitignore b/.idea/.idea.Netatmo/.idea/.gitignore new file mode 100644 index 0000000..909a383 --- /dev/null +++ b/.idea/.idea.Netatmo/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/modules.xml +/.idea.Netatmo.iml +/projectSettingsUpdater.xml +/contentModel.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/.idea.Netatmo/.idea/.name b/.idea/.idea.Netatmo/.idea/.name new file mode 100644 index 0000000..a402f23 --- /dev/null +++ b/.idea/.idea.Netatmo/.idea/.name @@ -0,0 +1 @@ +Netatmo \ No newline at end of file diff --git a/.idea/.idea.Netatmo/.idea/codeStyles/Project.xml b/.idea/.idea.Netatmo/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..6ccdaf0 --- /dev/null +++ b/.idea/.idea.Netatmo/.idea/codeStyles/Project.xml @@ -0,0 +1,23 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.Netatmo/.idea/codeStyles/codeStyleConfig.xml b/.idea/.idea.Netatmo/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/.idea.Netatmo/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.Netatmo/.idea/encodings.xml b/.idea/.idea.Netatmo/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/.idea.Netatmo/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.Netatmo/.idea/indexLayout.xml b/.idea/.idea.Netatmo/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/.idea.Netatmo/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.Netatmo/.idea/vcs.xml b/.idea/.idea.Netatmo/.idea/vcs.xml new file mode 100644 index 0000000..288b36b --- /dev/null +++ b/.idea/.idea.Netatmo/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/indexLayout.xml b/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Netatmo.sln b/Netatmo.sln new file mode 100644 index 0000000..2ad14f2 --- /dev/null +++ b/Netatmo.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Netatmo", "src\Netatmo\Netatmo.csproj", "{0E18F081-D50E-44B7-8DF7-42FC9F2E316E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Netatmo.Tests", "tests\Netatmo.Tests\Netatmo.Tests.csproj", "{14363A07-CF0F-466E-84ED-19158900CA19}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApp", "tests\TestApp\TestApp.csproj", "{50527DF5-B8F7-4DE2-9159-94CFE7F8A86B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{35DE6BA8-BAAC-4B8E-9492-256CA758B2BF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0E18F081-D50E-44B7-8DF7-42FC9F2E316E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0E18F081-D50E-44B7-8DF7-42FC9F2E316E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E18F081-D50E-44B7-8DF7-42FC9F2E316E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0E18F081-D50E-44B7-8DF7-42FC9F2E316E}.Release|Any CPU.Build.0 = Release|Any CPU + {14363A07-CF0F-466E-84ED-19158900CA19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {14363A07-CF0F-466E-84ED-19158900CA19}.Debug|Any CPU.Build.0 = Debug|Any CPU + {14363A07-CF0F-466E-84ED-19158900CA19}.Release|Any CPU.ActiveCfg = Release|Any CPU + {14363A07-CF0F-466E-84ED-19158900CA19}.Release|Any CPU.Build.0 = Release|Any CPU + {50527DF5-B8F7-4DE2-9159-94CFE7F8A86B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {50527DF5-B8F7-4DE2-9159-94CFE7F8A86B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {50527DF5-B8F7-4DE2-9159-94CFE7F8A86B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {50527DF5-B8F7-4DE2-9159-94CFE7F8A86B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {50527DF5-B8F7-4DE2-9159-94CFE7F8A86B} = {35DE6BA8-BAAC-4B8E-9492-256CA758B2BF} + {14363A07-CF0F-466E-84ED-19158900CA19} = {35DE6BA8-BAAC-4B8E-9492-256CA758B2BF} + EndGlobalSection +EndGlobal diff --git a/Netatmo.sln.DotSettings b/Netatmo.sln.DotSettings new file mode 100644 index 0000000..97d5bb5 --- /dev/null +++ b/Netatmo.sln.DotSettings @@ -0,0 +1,312 @@ + + False + True + ShowAndRun + True + Built-in: Full Cleanup + Built-in: Full Cleanup + False + Required + Required + Required + Required + ExpressionBody + ExpressionBody + Arithmetic + Arithmetic, Shift, Bitwise + True + CurrentType + False + True + True + True + True + 1 + 1 + False + False + False + False + False + False + NEVER + NEVER + False + NEVER + False + NEVER + True + False + False + False + True + True + CHOP_IF_LONG + CHOP_IF_LONG + True + True + CHOP_IF_LONG + CHOP_IF_LONG + CHOP_IF_LONG + CHOP_IF_LONG + CHOP_IF_LONG + <Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> + <TypePattern DisplayName="Non-reorderable types"> + <TypePattern.Match> + <Or> + <And> + <Kind Is="Interface" /> + <Or> + <HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" /> + <HasAttribute Name="System.Runtime.InteropServices.ComImport" /> + </Or> + </And> + <Kind Is="Struct" /> + <HasAttribute Name="JetBrains.Annotations.NoReorderAttribute" /> + <HasAttribute Name="JetBrains.Annotations.NoReorder" /> + </Or> + </TypePattern.Match> + </TypePattern> + + <TypePattern DisplayName="xUnit.net Test Classes" RemoveRegions="All"> + <TypePattern.Match> + <And> + <Kind Is="Class" /> + <HasMember> + <And> + <Kind Is="Method" /> + <HasAttribute Name="Xunit.FactAttribute" Inherited="True" /> + <HasAttribute Name="Xunit.TheoryAttribute" Inherited="True" /> + </And> + </HasMember> + </And> + </TypePattern.Match> + + <Entry DisplayName="Setup/Teardown Methods"> + <Entry.Match> + <Or> + <Kind Is="Constructor" /> + <And> + <Kind Is="Method" /> + <ImplementsInterface Name="System.IDisposable" /> + </And> + </Or> + </Entry.Match> + + <Entry.SortBy> + <Kind> + <Kind.Order> + <DeclarationKind>Constructor</DeclarationKind> + </Kind.Order> + </Kind> + </Entry.SortBy> + </Entry> + + + <Entry DisplayName="All other members" /> + + <Entry DisplayName="Test Methods" Priority="100"> + <Entry.Match> + <And> + <Kind Is="Method" /> + <HasAttribute Name="Xunit.FactAttribute" Inherited="false" /> + <HasAttribute Name="Xunit.TheoryAttribute" Inherited="false" /> + </And> + </Entry.Match> + + <Entry.SortBy> + <Name /> + </Entry.SortBy> + </Entry> + </TypePattern> + + <TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All"> + <TypePattern.Match> + <And> + <Kind Is="Class" /> + <Or> + <HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="true" /> + <HasAttribute Name="NUnit.Framework.TestFixtureSourceAttribute" Inherited="true" /> + <HasMember> + <And> + <Kind Is="Method" /> + <HasAttribute Name="NUnit.Framework.TestAttribute" Inherited="false" /> + <HasAttribute Name="NUnit.Framework.TestCaseAttribute" Inherited="false" /> + <HasAttribute Name="NUnit.Framework.TestCaseSourceAttribute" Inherited="false" /> + </And> + </HasMember> + </Or> + </And> + </TypePattern.Match> + + <Entry DisplayName="Setup/Teardown Methods"> + <Entry.Match> + <And> + <Kind Is="Method" /> + <Or> + <HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="true" /> + <HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="true" /> + <HasAttribute Name="NUnit.Framework.TestFixtureSetUpAttribute" Inherited="true" /> + <HasAttribute Name="NUnit.Framework.TestFixtureTearDownAttribute" Inherited="true" /> + <HasAttribute Name="NUnit.Framework.OneTimeSetUpAttribute" Inherited="true" /> + <HasAttribute Name="NUnit.Framework.OneTimeTearDownAttribute" Inherited="true" /> + </Or> + </And> + </Entry.Match> + </Entry> + + <Entry DisplayName="All other members" /> + + <Entry DisplayName="Test Methods" Priority="100"> + <Entry.Match> + <And> + <Kind Is="Method" /> + <HasAttribute Name="NUnit.Framework.TestAttribute" Inherited="false" /> + <HasAttribute Name="NUnit.Framework.TestCaseAttribute" Inherited="false" /> + <HasAttribute Name="NUnit.Framework.TestCaseSourceAttribute" Inherited="false" /> + </And> + </Entry.Match> + + <Entry.SortBy> + <Name /> + </Entry.SortBy> + </Entry> + </TypePattern> + + <TypePattern DisplayName="Default Pattern"> + <Entry DisplayName="Public Delegates" Priority="100"> + <Entry.Match> + <And> + <Access Is="Public" /> + <Kind Is="Delegate" /> + </And> + </Entry.Match> + + <Entry.SortBy> + <Name /> + </Entry.SortBy> + </Entry> + + <Entry DisplayName="Public Enums" Priority="100"> + <Entry.Match> + <And> + <Access Is="Public" /> + <Kind Is="Enum" /> + </And> + </Entry.Match> + + <Entry.SortBy> + <Name /> + </Entry.SortBy> + </Entry> + + <Entry DisplayName="Static Fields and Constants"> + <Entry.Match> + <Or> + <Kind Is="Constant" /> + <And> + <Kind Is="Field" /> + <Static /> + </And> + </Or> + </Entry.Match> + + <Entry.SortBy> + <Kind> + <Kind.Order> + <DeclarationKind>Constant</DeclarationKind> + <DeclarationKind>Field</DeclarationKind> + </Kind.Order> + </Kind> + </Entry.SortBy> + </Entry> + + <Entry DisplayName="Fields"> + <Entry.Match> + <And> + <Kind Is="Field" /> + <Not> + <Static /> + </Not> + </And> + </Entry.Match> + + <Entry.SortBy> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + + <Entry DisplayName="Constructors"> + <Entry.Match> + <Kind Is="Constructor" /> + </Entry.Match> + + <Entry.SortBy> + <Static/> + </Entry.SortBy> + </Entry> + + <Entry DisplayName="Properties, Indexers"> + <Entry.Match> + <Or> + <Kind Is="Property" /> + <Kind Is="Indexer" /> + </Or> + </Entry.Match> + </Entry> + + <Entry DisplayName="Interface Implementations" Priority="100"> + <Entry.Match> + <And> + <Kind Is="Member" /> + <ImplementsInterface /> + </And> + </Entry.Match> + + <Entry.SortBy> + <ImplementsInterface Immediate="true" /> + </Entry.SortBy> + </Entry> + + <Entry DisplayName="All other members" /> + + <Entry DisplayName="Nested Types"> + <Entry.Match> + <Kind Is="Type" /> + </Entry.Match> + </Entry> + </TypePattern> +</Patterns> + + True + Replace + True + True + True + Replace + Replace + False + True + False + True + False + False + True + False + True + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy><Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Interfaces"><ElementKinds><Kind Name="INTERFACE" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy> + <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"><ElementKinds><Kind Name="FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + True + True + True + True + True + True \ No newline at end of file diff --git a/src/.gitignore b/src/.gitignore deleted file mode 100644 index 343245e..0000000 --- a/src/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -# Default ignored files -/.idea/shelf/ -/.idea/workspace.xml - -# Datasource local storage ignored files -/.idea/.idea.Netatmo/.idea/dataSources/ -dataSources.local.xml - -# Editor-based HTTP Client requests -/.idea/httpRequests/ -rest-client.private.env.json -http-client.private.env.json \ No newline at end of file diff --git a/src/Netatmo.Tests/AirClient.cs b/src/Netatmo.Tests/AirClient.cs deleted file mode 100644 index 7316b4f..0000000 --- a/src/Netatmo.Tests/AirClient.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Net.Http; -using System.Threading.Tasks; -using FluentAssertions; -using Flurl.Http.Testing; -using Moq; -using Netatmo.Enums; -using Netatmo.Models.Client.Air; -using NodaTime; -using Xunit; - -namespace Netatmo.Tests -{ - public class AirClient : IDisposable - { - private readonly HttpTest httpTest; - - public AirClient() - { - httpTest = new HttpTest(); - httpTest.Configure(Configuration.ConfigureRequest); - } - - public void Dispose() - { - httpTest.Dispose(); - } - - [Fact] - public async Task GetStationsData_Should_Return_DataResponse_With_AirData() - { - var accessToken = "Super-Access-Token"; - var credentialManagerMock = new Mock(); - credentialManagerMock.Setup(x => x.AccessToken).Returns(accessToken); - - httpTest.RespondWith( - "{\"body\": {\"devices\": [{\"_id\": \"70:xx:xx:xx:xx:c2\",\"cipher_id\": \"enc:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa28Zn\",\"date_setup\": 1548316279,\"last_setup\": 1548316279,\"type\": \"NHC\",\"last_status_store\": 1548331813,\"module_name\": \"Indoor\",\"firmware\": 45,\"last_upgrade\": 1548316280,\"wifi_status\": 49,\"reachable\": true,\"co2_calibrating\": true,\"station_name\": \"Healthy ConX\",\"data_type\": [\"Temperature\",\"CO2\",\"Humidity\",\"Noise\",\"Pressure\",\"health_idx\"],\"place\": {\"altitude\": 491.70001220703,\"country\": \"CH\",\"timezone\": \"Europe/Zurich\",\"location\": [8.3085069,47.0450306]},\"dashboard_data\": {\"time_utc\": 1548331811,\"Temperature\": 22.1,\"CO2\": 647,\"Humidity\": 33,\"Noise\": 44,\"Pressure\": 1018.3,\"AbsolutePressure\": 960.4,\"health_idx\": 0,\"min_temp\": 17.3,\"max_temp\": 23.6,\"date_min_temp\": 1548316040,\"date_max_temp\": 1548316058}}],\"user\": {\"mail\": \"a@mail.ch\",\"administrative\": {\"lang\": \"en-US\",\"reg_locale\": \"en-US\",\"country\": \"CH\",\"unit\": 0,\"windunit\": 0,\"pressureunit\": 0,\"feel_like_algo\": 0}}},\"status\": \"ok\",\"time_exec\": 0.038990020751953,\"time_server\": 1548331875}"); - - var sut = new Netatmo.AirClient("https://api.netatmo.com/", credentialManagerMock.Object); - var result = await sut.GetHomeCoachsData(); - - httpTest - .ShouldHaveCalled("https://api.netatmo.com/api/gethomecoachsdata") - .WithVerb(HttpMethod.Post) - .WithOAuthBearerToken(accessToken) - .WithContentType("application/json").WithRequestJson(new GetHomeCoachsDataRequest()) - .Times(1); - - result.Body.Should().BeOfType(); - result.Body.Devices[0].DashboardData.Noise.Should().Be(44); - result.Body.Devices[0].WifiStrength.Should().Be(WifiStrengthEnum.Good); - result.Body.Devices[0].DashboardData.HumidityPercent.Should().Be(33); - result.Body.Devices[0].Place.Timezone.Should().Be(DateTimeZoneProviders.Tzdb["Europe/Zurich"]); - } - } -} \ No newline at end of file diff --git a/src/Netatmo.Tests/ClassData/Energy/GetRoomMeasureArgumentExceptionData.cs b/src/Netatmo.Tests/ClassData/Energy/GetRoomMeasureArgumentExceptionData.cs deleted file mode 100644 index cc2b021..0000000 --- a/src/Netatmo.Tests/ClassData/Energy/GetRoomMeasureArgumentExceptionData.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using Netatmo.Models.Client.Energy; -using NodaTime; - -namespace Netatmo.Tests.ClassData.Energy -{ - public class GetRoomMeasureArgumentExceptionData : IEnumerable - { - public IEnumerator GetEnumerator() - { - yield return new object[] { new GetRoomMeasureParameters(), "Home Id shouldn't be null" }; - yield return new object[] { new GetRoomMeasureParameters { HomeId = "5a327cbdb05a2133678b5d3e" }, "Room Id shouldn't be null" }; - yield return new object[] { new GetRoomMeasureParameters { HomeId = "5a327cbdb05a2133678b5d3e", RoomId = "2255031728" }, "Scale shouldn't be null" }; - yield return new object[] { new GetRoomMeasureParameters { HomeId = "5a327cbdb05a2133678b5d3e", RoomId = "2255031728", Scale = Scale.Max }, "Type shouldn't be null" }; - yield return new object[] - { - new GetRoomMeasureParameters { HomeId = "5a327cbdb05a2133678b5d3e", RoomId = "2255031728", Scale = Scale.Max, Type = ThermostatMeasurementType.DateMinTemp }, - "Type shouldn't be allow for this scale" - }; - yield return new object[] - { - new GetRoomMeasureParameters - { - HomeId = "5a327cbdb05a2133678b5d3e", - RoomId = "2255031728", - Scale = Scale.Max, - Type = ThermostatMeasurementType.Temperature, - Limit = 2000 - }, - "Limit should be between 0 and 1024" - }; - yield return new object[] - { - new GetRoomMeasureParameters - { - HomeId = "5a327cbdb05a2133678b5d3e", - RoomId = "2255031728", - Scale = Scale.Max, - Type = ThermostatMeasurementType.Temperature, - Limit = -42 - }, - "Limit should be between 0 and 1024" - }; - yield return new object[] - { - new GetRoomMeasureParameters - { - HomeId = "5a327cbdb05a2133678b5d3e", - RoomId = "2255031728", - Scale = Scale.Max, - Type = ThermostatMeasurementType.Temperature, - BeginAt = Instant.FromDateTimeUtc(DateTime.SpecifyKind(new DateTime(2018, 4, 30), DateTimeKind.Utc)), - EndAt = Instant.FromDateTimeUtc(DateTime.SpecifyKind(new DateTime(2017, 4, 30), DateTimeKind.Utc)) - }, - "BeginAt should be lower than EndAt" - }; - } - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - } -} \ No newline at end of file diff --git a/src/Netatmo.Tests/CredentialManager.cs b/src/Netatmo.Tests/CredentialManager.cs deleted file mode 100644 index a4efd9d..0000000 --- a/src/Netatmo.Tests/CredentialManager.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using System.Net.Http; -using System.Threading.Tasks; -using FluentAssertions; -using Flurl.Http.Testing; -using Netatmo.Models; -using NodaTime; -using NodaTime.Testing; -using Xunit; - -namespace Netatmo.Tests -{ - public class CredentialManager : IDisposable - { - private readonly HttpTest httpTest; - - public CredentialManager() - { - httpTest = new HttpTest(); - } - - public void Dispose() - { - httpTest.Dispose(); - } - - [Fact] - public async Task GenerateToken_Should_Acquire_Excepted_CredentialToken() - { - var expectedToken = new { access_token = "2YotnFZFEjr1zCsicMWpAA", expires_in = 10800, refresh_token = "tGzv3JOkF0XG5Qx2TlKWIA" }; - - httpTest.RespondWithJson(expectedToken); - - var sut = new Netatmo.CredentialManager("https://api.netatmo.com/", "clientId", "clientSecret", SystemClock.Instance); - - await sut.GenerateToken("username@email.com", "p@$$W0rd", - new[] - { - Scope.CameraAccess, Scope.CameraRead, Scope.CameraWrite, Scope.HomecoachRead, Scope.PresenceAccess, Scope.PresenceRead, Scope.StationRead, - Scope.StationWrite, Scope.ThermostatRead - }); - - var token = sut.CredentialToken; - - httpTest - .ShouldHaveCalled("https://api.netatmo.com/oauth2/token") - .WithVerb(HttpMethod.Post) - .WithContentType("application/x-www-form-urlencoded") - .WithRequestBody( - "grant_type=password&client_id=clientId&client_secret=clientSecret&username=username%40email.com&password=p%40%24%24W0rd&scope=access_camera+read_camera+write_camera+read_homecoach+access_presence+read_presence+read_station+write_thermostat+read_thermostat") - .Times(1); - - token.Should().BeOfType(); - token.AccessToken.Should().Be(expectedToken.access_token); - token.RefreshToken.Should().Be(expectedToken.refresh_token); - token.ExpiresAt.Should().Be(token.ReceivedAt.Plus(Duration.FromSeconds(expectedToken.expires_in))); - } - - [Fact] - public void ProvideOAuth2Token_Should_Provide_Token_From_Existing() - { - var expectedToken = new { access_token = "2YotnFZFEjr1zCsicMWpAA", expires_in = 20 }; - - httpTest.RespondWithJson(expectedToken); - - var sut = new Netatmo.CredentialManager("https://api.netatmo.com/", "clientId", "clientSecret", SystemClock.Instance); - - sut.ProvideOAuth2Token(expectedToken.access_token); - - var token = sut.CredentialToken; - - token.Should().BeOfType(); - token.AccessToken.Should().Be(expectedToken.access_token); - token.RefreshToken.Should().BeNull(); - token.ExpiresAt.Should().Be(token.ReceivedAt.Plus(Duration.FromSeconds(expectedToken.expires_in))); - } - - [Fact] - public async Task RefreshToken_Should_Refresh_Token() - { - var token = new { access_token = "2YotnFZFEjr1zCsicMWpAA", expires_in = 10800, refresh_token = "tGzv3JOkF0XG5Qx2TlKWIA" }; - - var expectedToken = new { access_token = "dGVzdGNsaWVudDpzZWNyZXQ", expires_in = 10800, refresh_token = "fdb8fdbecf1d03ce5e6125c067733c0d51de209c" }; - - httpTest.RespondWithJson(token); - httpTest.RespondWithJson(expectedToken); - - var fakeClock = new FakeClock(SystemClock.Instance.GetCurrentInstant(), Duration.FromMinutes(-2)); - - var sut = new Netatmo.CredentialManager("https://api.netatmo.com/", "clientId", "clientSecret", fakeClock); - - await sut.GenerateToken("username@email.com", "p@$$W0rd"); - var oldToken = sut.CredentialToken; - await sut.RefreshToken(); - var refreshedToken = sut.CredentialToken; - - httpTest - .ShouldHaveCalled("https://api.netatmo.com/oauth2/token") - .WithVerb(HttpMethod.Post) - .WithContentType("application/x-www-form-urlencoded") - .WithRequestBody( - $"grant_type=refresh_token&client_id=clientId&client_secret=clientSecret&refresh_token={oldToken.RefreshToken}") - .Times(1); - - refreshedToken.Should().BeOfType(); - refreshedToken.AccessToken.Should().Be(expectedToken.access_token); - refreshedToken.RefreshToken.Should().Be(expectedToken.refresh_token); - refreshedToken.ExpiresAt.Should().Be(refreshedToken.ReceivedAt.Plus(Duration.FromSeconds(expectedToken.expires_in))); - refreshedToken.Should().NotBe(oldToken); - } - } -} \ No newline at end of file diff --git a/src/Netatmo.Tests/EnergyClient.cs b/src/Netatmo.Tests/EnergyClient.cs deleted file mode 100644 index 1854f6e..0000000 --- a/src/Netatmo.Tests/EnergyClient.cs +++ /dev/null @@ -1,302 +0,0 @@ -using System; -using System.Net.Http; -using System.Threading.Tasks; -using FluentAssertions; -using Flurl.Http.Testing; -using Moq; -using Netatmo.Enums; -using Netatmo.Models.Client; -using Netatmo.Models.Client.Energy; -using Netatmo.Models.Client.Energy.RoomMeasure; -using Netatmo.Tests.ClassData.Energy; -using NodaTime; -using Xunit; - -namespace Netatmo.Tests -{ - public class EnergyClient : IDisposable - { - private readonly string accessToken; - - private readonly HttpTest httpTest; - private Mock credentialManagerMock; - - public EnergyClient() - { - httpTest = new HttpTest(); - httpTest.Configure(Configuration.ConfigureRequest); - - accessToken = "Super-Access-Token"; - credentialManagerMock = new Mock(); - credentialManagerMock.Setup(x => x.AccessToken).Returns(accessToken); - } - - public void Dispose() - { - httpTest.Dispose(); - } - - [Fact] - public async Task CreateHomeSchedule_Should_Return_Expected_Result() - { - var parameters = new CreateHomeScheduleRequest("5a327cbdb05a2133678b5d3e", 14, 16, "Cat schedule"); - httpTest.RespondWithJson(new CreateHomeScheduleResponse - { - ScheduleId = "5a819e6113475d09c28b497a", Status = "ok", TimeExec = 0.036107063293457, TimeServer = Instant.FromUnixTimeSeconds(1518023467) - }); - - var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); - await sut.CreateHomeSchedule(parameters); - - httpTest - .ShouldHaveCalled("https://api.netatmo.com/api/createnewhomeschedule") - .WithVerb(HttpMethod.Post) - .WithOAuthBearerToken(accessToken) - .WithContentType("application/json") - .WithRequestJson( - new CreateHomeScheduleRequest( - parameters.HomeId, - parameters.HgTemp, - parameters.AwayTemp, - parameters.Name, - new Timetable[0], - new Zone[0])) - .Times(1); - } - - [Fact] - public async Task DeleteHomeSchedule_Should_Return_Expected_Result() - { - var homeId = "5a327cbdb05a2133678b5d3e"; - var scheduleId = "5a327cbdb05a2133678b5d3f"; - httpTest.RespondWithJson(new DataResponse { Status = "ok", TimeExec = 0.036107063293457, TimeServer = Instant.FromUnixTimeSeconds(1518023467) }); - - var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); - await sut.DeleteHomeSchedule(homeId, scheduleId); - - httpTest - .ShouldHaveCalled("https://api.netatmo.com/api/deletehomeschedule") - .WithVerb(HttpMethod.Post) - .WithOAuthBearerToken(accessToken) - .WithContentType("application/json").WithRequestJson(new DeleteHomeScheduleRequest { HomeId = homeId, ScheduleId = scheduleId }) - .Times(1); - } - - [Fact] - public async Task GetHomesData_Should_Return_DataResponse_With_HomesData() - { - httpTest.RespondWith( - "{\"body\":{\"homes\":[{\"id\":\"5a327cbdb05a2133678b5d3e\",\"name\":\"test\",\"altitude\":88,\"coordinates\":[2.2395809,48.829662],\"country\":\"FR\",\"timezone\":\"Europe\\/Paris\",\"rooms\":[{\"id\":\"2255031728\",\"name\":\"Salon\",\"type\":\"livingroom\",\"module_ids\":[\"04:00:00:23:f2:10\"],\"measure_offset_NAPlug_temperature\":0,\"measure_offset_NAPlug_estimated_temperature\":0},{\"id\":\"2539094912\",\"name\":\"Chambre\",\"type\":\"bedroom\",\"module_ids\":[\"09:00:00:00:0b:bd\"],\"measure_offset_NAPlug_temperature\":0,\"measure_offset_NAPlug_estimated_temperature\":0}],\"modules\":[{\"id\":\"70:ee:50:23:d7:a8\",\"type\":\"NAPlug\",\"name\":\"Relais\",\"setup_date\":1513259804,\"modules_bridged\":[\"04:00:00:23:f2:10\",\"09:00:00:00:0b:bd\"]},{\"id\":\"04:00:00:23:f2:10\",\"type\":\"NATherm1\",\"name\":\"Thermostat\",\"setup_date\":1513259817,\"room_id\":\"2255031728\",\"bridge\":\"70:ee:50:23:d7:a8\"},{\"id\":\"09:00:00:00:0b:bd\",\"type\":\"NRV\",\"name\":\"Vanne Salon\",\"setup_date\":1513260804,\"room_id\":\"2539094912\",\"bridge\":\"70:ee:50:23:d7:a8\"}],\"schedules\":[{\"away_temp\":12,\"default\":true,\"hg_temp\":7,\"timetable\":[{\"m_offset\":0,\"zone_id\":1},{\"m_offset\":420,\"zone_id\":3},{\"m_offset\":450,\"zone_id\":0},{\"m_offset\":480,\"zone_id\":4},{\"m_offset\":1140,\"zone_id\":0},{\"m_offset\":1290,\"zone_id\":3},{\"m_offset\":1320,\"zone_id\":1},{\"m_offset\":1860,\"zone_id\":3},{\"m_offset\":1890,\"zone_id\":0},{\"m_offset\":1920,\"zone_id\":4},{\"m_offset\":2580,\"zone_id\":0},{\"m_offset\":2730,\"zone_id\":3},{\"m_offset\":2760,\"zone_id\":1},{\"m_offset\":3300,\"zone_id\":3},{\"m_offset\":3330,\"zone_id\":0},{\"m_offset\":3360,\"zone_id\":4},{\"m_offset\":4020,\"zone_id\":0},{\"m_offset\":4170,\"zone_id\":3},{\"m_offset\":4200,\"zone_id\":1},{\"m_offset\":4740,\"zone_id\":3},{\"m_offset\":4770,\"zone_id\":0},{\"m_offset\":4800,\"zone_id\":4},{\"m_offset\":5460,\"zone_id\":0},{\"m_offset\":5610,\"zone_id\":3},{\"m_offset\":5640,\"zone_id\":1},{\"m_offset\":6180,\"zone_id\":3},{\"m_offset\":6210,\"zone_id\":0},{\"m_offset\":6240,\"zone_id\":4},{\"m_offset\":6900,\"zone_id\":0},{\"m_offset\":7050,\"zone_id\":3},{\"m_offset\":7080,\"zone_id\":1},{\"m_offset\":7620,\"zone_id\":3},{\"m_offset\":7650,\"zone_id\":0},{\"m_offset\":8490,\"zone_id\":3},{\"m_offset\":8520,\"zone_id\":1},{\"m_offset\":9060,\"zone_id\":3},{\"m_offset\":9090,\"zone_id\":0},{\"m_offset\":9930,\"zone_id\":3},{\"m_offset\":9960,\"zone_id\":1}],\"zones\":[{\"type\":0,\"id\":0,\"rooms\":[{\"id\":\"2255031728\",\"therm_setpoint_temperature\":19},{\"room_id\":\"2539094912\",\"therm_setpoint_temperature\":17}]},{\"type\":1,\"id\":1,\"rooms\":[{\"id\":\"2255031728\",\"therm_setpoint_temperature\":16},{\"id\":\"2539094912\",\"therm_setpoint_temperature\":17}]},{\"type\":8,\"id\":3,\"rooms\":[{\"id\":\"2255031728\",\"therm_setpoint_temperature\":19},{\"id\":\"2539094912\",\"therm_setpoint_temperature\":17}]},{\"type\":5,\"id\":4,\"rooms\":[{\"id\":\"2255031728\",\"therm_setpoint_temperature\":16},{\"id\":\"2539094912\",\"therm_setpoint_temperature\":16}]}],\"id\":\"5a327cbdb05a2133678b5d3f\",\"selected\":true,\"type\":\"therm\"}],\"therm_setpoint_default_duration\":180,\"therm_mode\":\"schedule\"}],\"user\":{\"email\":\"example@domain.com\",\"language\":\"fr-FR\",\"locale\":\"en-FR\",\"feel_like_algorithm\":0,\"unit_pressure\":0,\"unit_system\":0,\"unit_wind\":0,\"id\":\"user_id\"}},\"status\":\"ok\",\"time_exec\":0.08151913,\"time_server\":1518022817}"); - - var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); - var result = await sut.GetHomesData(); - - httpTest - .ShouldHaveCalled("https://api.netatmo.com/api/homesdata") - .WithVerb(HttpMethod.Post) - .WithOAuthBearerToken(accessToken) - .WithContentType("application/json").WithRequestJson(new GetHomesDataRequest()) - .Times(1); - - result.Body.Should().BeOfType(); - result.Body.Homes[0].Modules[0].ModulesBridged.Should().Equal("04:00:00:23:f2:10", "09:00:00:00:0b:bd"); - } - - [Fact] - public async Task GetHomeStatus_Should_Return_DataResponse_With_HomeStatus() - { - var homeId = "5a327cbdb05a2133678b5d3e"; - httpTest.RespondWith( - "{\"status\":\"ok\",\"time_server\":1518023129,\"body\":{\"home\":{\"modules\":[{\"id\":\"70:ee:50:23:d7:a8\",\"type\":\"NAPlug\",\"rf_strength\":104,\"wifi_strength\":38},{\"id\":\"04:00:00:23:f2:10\",\"reachable\":true,\"type\":\"NATherm1\",\"firmware_revision\":65,\"rf_strength\":26,\"battery_level\":4478,\"boiler_valve_comfort_boost\":false,\"boiler_status\":false,\"anticipating\":false,\"bridge\":\"70:ee:50:23:d7:a8\",\"battery_state\":\"full\"},{\"id\":\"09:00:00:00:0b:bd\",\"reachable\":true,\"type\":\"NRV\",\"firmware_revision\":51,\"rf_strength\":44,\"battery_level\":2982,\"bridge\":\"70:ee:50:23:d7:a8\",\"battery_state\":\"high\"}],\"rooms\":[{\"id\":\"2255031728\",\"reachable\":true,\"therm_measured_temperature\":25.3,\"therm_setpoint_temperature\":16,\"therm_setpoint_mode\":\"schedule\",\"therm_setpoint_start_time\":1517986800,\"therm_setpoint_end_time\":0},{\"id\":\"2539094912\",\"reachable\":true,\"therm_measured_temperature\":24,\"heating_power_request\":0,\"therm_setpoint_temperature\":16,\"therm_setpoint_mode\":\"schedule\",\"therm_setpoint_start_time\":1517986800,\"therm_setpoint_end_time\":0}],\"id\":\"5a327cbdb05a2133678b5d3e\"}}}"); - - var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); - var result = await sut.GetHomeStatus(homeId); - - httpTest - .ShouldHaveCalled("https://api.netatmo.com/api/homestatus") - .WithVerb(HttpMethod.Post) - .WithOAuthBearerToken(accessToken) - .WithContentType("application/json").WithRequestJson(new GetHomeStatusRequest { HomeId = homeId }) - .Times(1); - - result.Body.Should().BeOfType(); - result.Body.Home.Modules[0].WifiStatus.Should().Be(WifiStrengthEnum.Good); - result.Body.Home.Modules[0].RfStatus.Should().Be(RfStrengthEnum.Low); - - result.Body.Home.Modules[1].WifiStatus.Should().Be(WifiStrengthEnum.Undefined); - result.Body.Home.Modules[1].BatteryStatus.Should().Be(BatteryLevelEnum.Full); - - result.Body.Home.Modules[2].BatteryStatus.Should().Be(BatteryLevelEnum.High); - } - - [Fact] - public async Task GetRoomMeasure_Should_Return_TemperatureSteps() - { - var parameters = new GetRoomMeasureParameters - { - HomeId = "5a327cbdb05a2133678b5d3e", RoomId = "2255031728", Scale = Scale.Max, Type = ThermostatMeasurementType.Temperature - }; - - httpTest.RespondWith( - "{\"body\":[{\"beg_time\":1513259100,\"step_time\":1800,\"value\":[[27.9],[27.1],[26.2],[25.4],[25.8],[26.2],[26.7],[26.9],[27],[27.1],[27.2],[27],[26.8],[26.6],[26.5],[26.3],[26.3],[26.3],[26.2],[26.2],[26.2],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26],[26],[26.1],[26],[26],[26],[26],[26],[25.9],[24.8],[24],[23.6],[23.5],[23.2],[23],[22.9],[22.7],[22.5],[22.4],[22.4],[22.6],[22.8],[23.1],[23.2],[23.4],[23.4],[23.3],[23.1],[22.9],[22.5],[22.2],[21.9],[21.6],[21.6],[21.4],[21.2],[21.1],[21],[20.9],[20.8],[20.7],[20.7],[20.6],[20.6],[20.6],[20.5],[20.5],[20.5],[20.4],[20.4],[20.4],[20.4],[20.4],[20.3],[20.3],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.3],[20.3],[20.3],[20.3],[20.2],[20.2],[20.1],[20],[20],[19.9],[19.8],[19.8],[19.8],[19.7],[19.7],[19.7],[19.6],[19.9],[20.2],[20.6],[20.6],[20.7],[20.6],[20.7],[20.7],[20.7],[20.8],[20.7],[20.8],[20.7],[20.8],[20.5],[20.2],[20],[19.9],[19.7],[19.6],[19.5],[19.5],[19.4],[19.4],[19.4],[19.5],[19.5],[19.6],[19.6],[19.6],[19.7],[19.7],[19.7],[19.7],[19.7],[19.7],[19.6],[19.6],[19.5],[19.4],[19.4],[19.3],[19.3],[19.3],[19.3],[19.2],[19.2],[19.3],[20],[20.6],[20.8],[20.9],[20.8],[20.9],[21],[20.8],[20.9],[20.9],[20.7],[20.8],[20.8],[20.7],[20.4],[20.2],[20],[19.9],[19.7],[19.6],[19.6],[19.5],[19.7],[20.3],[20.6],[21],[21.3],[21.7],[21.9],[21.7],[21.6],[21.6],[21.5],[21.6],[21.9],[22.1],[22],[22],[22.1],[22.2],[22.3],[22.2],[21.9],[21.5],[21.1],[20.7],[20.5],[20.3],[20.4],[20.6],[20.7],[20.7],[20.8],[20.7],[20.8],[20.7],[20.8],[20.7],[20.8],[20.7],[20.8],[20.8],[20.5],[20.2],[20],[19.9],[19.7],[19.7],[19.6],[19.5],[19.7],[20.2],[20.6],[21],[21.4],[21.7],[21.7],[21.5],[21.2],[21],[21],[21.2],[21.5],[21.8],[22.2],[22.2],[22.3],[22.6],[23.4],[23.8],[24.2],[24.4],[24.4],[24.4],[24.5],[24.5],[24.5],[24.6],[24.6],[24.6],[24.6],[24.6],[24.7],[24.7],[24.7],[24.7],[24.8],[24.8],[24.8],[24.9],[24.9],[24.9],[25],[25],[25.1],[25.1],[25.1],[25.2],[25.2],[25.3],[25.6],[25.9],[26.1],[26.4],[26.5],[26.4],[26.3],[26.2],[26.3],[26.4],[26.5],[26.7],[26.8],[26.7],[26.9],[27],[27],[26.7],[26.6],[26.5],[26.3],[26.2],[26.1],[26],[26],[26],[26],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[26],[26],[26],[26],[26],[26.1],[26.1],[25.2],[23.9],[23.2],[24.1],[25.1],[25.9],[26.3],[26.6],[26.6],[26.2],[25.7],[25],[24.4],[25.1],[25.7],[26.2],[26.3],[26.1],[25.9],[25.2],[24],[22.9],[21.9],[21],[20.2],[19.6],[19.3],[19.1],[19],[18.9],[18.8],[18.7],[18.6],[18.5],[18.4],[18.3],[18.2],[18.1],[18],[17.9],[17.8],[17.6],[17.4],[17.3],[17.1],[17],[17],[17.3],[18.2],[20.2],[21.9],[23.2],[24.1],[24.8],[25.2],[24.8],[23.9],[24.3],[25],[25.6],[26],[26.2],[26.3],[26.4],[26.4],[26.5],[26.5],[26.4],[26.3],[26.2],[26.1],[26],[25.9],[25.9],[25.9],[25.8],[25.8],[25.8],[25.8],[25.8],[25.8],[25.8],[25.8],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[26],[26],[26],[26],[26],[26],[26],[26.1],[26.1],[26.1],[26.2],[26.2],[26.2],[26.2],[26.2],[26.3],[26.3],[26.3],[26.3],[26.2],[26.2],[26.2],[26.2],[26.2],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.3],[26.3],[26.4],[26.4],[26.5],[26.4],[26.4],[26.3],[26.3],[26.3],[26.3],[26.2],[26.2],[26.2],[26.2],[26.2],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26],[26],[25.9],[25.9],[25.8],[25.8],[25.8],[25.7],[25.7],[25.7],[25.7],[25.7],[25.7],[25.7],[25.8],[25.9],[26],[26],[24.8],[23.8],[24.4],[24.9],[25.3],[25.8],[26.1],[26.4],[26.6],[26.7],[26.7],[26.8],[26.9],[26.9],[27.1],[27.2],[27.3],[27.3],[27.3],[27.3],[27.2],[27.1],[27],[26.9],[26.8],[26.7],[26.6],[26.5],[26.5],[26.4],[26.4],[26.3],[26.2],[26.1],[26.1],[26],[26],[25.9],[25.9],[25.9],[25.8],[25.8],[25.8],[25.9],[26],[26.1],[26.2],[26.2],[26.3],[25.1],[24.9],[25.2],[25.6],[26],[26.4],[26.6],[26.7],[26.7],[26.7],[26.6],[26.6],[26.7],[26.7],[26.9],[26.6],[26.5],[26.6],[26.7],[26.7],[26.5],[26.5],[26.4],[26.4],[26.4],[26.4],[26.4],[26.3],[26.3],[26.2],[26.2],[26.1],[26.1],[26],[26],[25.9],[25.9],[25.9],[25.8],[25.8],[25.8],[25.8],[25.8],[25.8],[25.9],[25.9],[25.9],[25.9],[26],[26.1],[25.9],[24.8],[25.2],[25.7],[26.3],[26.6],[26.7],[26.8],[26.8],[26.7],[26.9],[27],[27.1],[27.1],[26.8],[26.3],[25.4],[24.6],[23.8],[23.2],[22.6],[22.2],[21.9],[21.6],[21.5],[21.4],[21.3],[21.2],[21.1],[21],[21],[20.9],[20.8],[20.8],[20.7],[20.7],[20.6],[20.6],[20.6],[20.5],[20.5],[20.4],[20.4],[20.3],[20.2],[20.2],[20.2],[20.3],[20.5],[20.7],[20.9],[21.1],[21.2],[21.3],[21.3],[21.3],[21.3],[21.3],[21.4],[21.5],[21.5],[21.6],[21.6],[21.6],[21.6],[21.6],[21.4],[21],[20.8],[20.6],[20.4],[20.3],[20.2],[20.4],[20.5],[20.5],[20.5],[20.5],[20.5],[20.5],[20.6],[20.5],[20.6],[20.5],[20.6],[20.5],[20.6],[20.4],[20.3],[20.3],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.3],[20.3],[20.3],[20.4],[20.4],[20.5],[20.5],[20.4],[20.4],[20.4],[20.4],[20.4],[20.4],[20.3],[20.3],[20.3],[20.3],[20.3],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.5],[20.7],[20.7],[20.8],[20.7],[20.7],[20.7],[20.8],[20.8],[20.7],[20.8],[20.7],[20.8],[20.7],[20.5],[20.4],[20.3],[20.2],[20.2],[20.1],[20.1],[20.1],[20.1],[20.1],[20.1],[20.1],[20.1],[20.1],[20.2],[20.2],[20.3],[20.4],[20.3],[20.3],[20.3],[20.2],[20.2],[20.1],[20],[20],[19.9],[19.9],[19.9],[19.9],[19.8],[19.8],[19.8],[19.8],[20],[20.3],[20.7],[20.7],[20.8],[20.7],[20.8],[20.7],[20.8],[20.7],[20.8],[20.7],[20.8],[20.7],[20.4],[20.1],[20],[19.9],[19.7],[19.7],[19.5],[19.5],[19.5],[19.4],[19.4],[19.4],[19.4],[19.4],[19.4],[19.4],[19.4],[19.5],[19.7],[19.7],[19.6],[19.6],[19.5],[19.5],[19.5],[19.4],[19.4],[19.4],[19.3],[19.3],[19.3],[19.3],[19.3],[19.4],[20.2],[20.7],[20.9],[20.7],[20.8],[20.8],[20.7],[20.8],[20.7],[20.7],[20.8],[20.7],[20.8],[20.7],[20.4],[20.1],[19.8],[19.7],[19.6],[19.5],[19.4],[19.4],[19.5],[19.9],[20.5],[20.8],[21],[21.3],[21.3],[21.1],[20.9],[20.9],[21.2],[21.5],[21.8],[22.1],[22.2],[22.3],[22.3],[22.4],[22.4],[22.1],[21.7],[21.3],[21],[20.7],[20.5],[20.4],[20.6],[20.7],[20.7],[20.9],[20.8],[20.8],[20.8],[20.8],[20.9],[20.8],[20.8],[20.8],[20.8],[20.9],[20.6],[20.4],[20.3],[20.2],[20.1],[20.1],[20],[19.9],[20.2],[20.7],[21.2],[21.7],[21.9],[22],[21.9],[21.6],[21.5],[21.6],[21.8],[22]]},{\"beg_time\":1514992500,\"step_time\":1800,\"value\":[[22.8],[22.9],[22.8],[22.7],[22.8],[22.8],[22.7],[22.3],[21.8],[21.4],[21.1],[20.8],[20.6],[20.6],[20.8],[20.8],[20.9],[20.8],[20.9],[20.9],[20.9],[20.9],[20.9],[20.9],[20.9],[20.9],[20.9],[20.7],[20.6],[20.4],[20.4],[20.3],[20.3],[20.3],[20.3],[20.6],[21.2],[21.4],[21.6],[21.8],[22.1],[22.2],[22],[21.9],[21.9],[22],[22.3],[22.5],[22.6],[22.7],[22.8],[22.8],[22.9],[22.6],[22.3],[21.7],[21.4],[21.1],[20.9],[20.7],[20.5],[20.7]]}],\"status\":\"ok\",\"time_exec\":0.79246497154236,\"time_server\":1518023284}"); - - var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); - var result = await sut.GetRoomMeasure(parameters); - - httpTest - .ShouldHaveCalled("https://api.netatmo.com/api/getroommeasure") - .WithVerb(HttpMethod.Post) - .WithOAuthBearerToken(accessToken) - .WithContentType("application/json").WithRequestJson(new GetRoomMeasureRequest - { - HomeId = parameters.HomeId, RoomId = parameters.RoomId, Scale = parameters.Scale.Value, Type = parameters.Type.Value - }) - .Times(1); - - result.Body[0].BeginAt.Should().Be(Instant.FromDateTimeUtc(DateTime.SpecifyKind(new DateTime(2017, 12, 14, 13, 45, 0), DateTimeKind.Utc))); - result.Body.Length.Should().Be(2); - result.Body[0].Values[0][0].Should().Be(27.9); - result.Body[0].Values[1][0].Should().Be(27.1); - } - - [Fact] - public void GetRoomMeasure_With_Bad_Type_Should_Throw_ArgumentException() - { - var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); - Func actTemperatureStep = async () => - { - await sut.GetRoomMeasure(new GetRoomMeasureParameters - { - HomeId = "5a327cbdb05a2133678b5d3e", RoomId = "2255031728", Scale = Scale.Max, Type = ThermostatMeasurementType.Temperature - }); - }; - - actTemperatureStep - .Should().Throw() - .WithMessage("TemperatureStep should be used with a temperature measurement"); - - Func actDateTemperatureStep = async () => - { - await sut.GetRoomMeasure(new GetRoomMeasureParameters - { - HomeId = "5a327cbdb05a2133678b5d3e", RoomId = "2255031728", Scale = Scale.OneMonth, Type = ThermostatMeasurementType.DateMinTemp - }); - }; - - actDateTemperatureStep - .Should().Throw() - .WithMessage("DateTemperatureStep should be used with a date of temperature measurement"); - } - - [Fact] - public async Task RenameHomeSchedule_Should_Return_Expected_Result() - { - var homeId = "5a327cbdb05a2133678b5d3e"; - var scheduleId = "5a327cbdb05a2133678b5d3f"; - var name = "Cat schedule"; - httpTest.RespondWithJson(new DataResponse { Status = "ok", TimeExec = 0.036107063293457, TimeServer = Instant.FromUnixTimeSeconds(1518023467) }); - - var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); - await sut.RenameHomeSchedule(homeId, scheduleId, name); - - httpTest - .ShouldHaveCalled("https://api.netatmo.com/api/renamehomeschedule") - .WithVerb(HttpMethod.Post) - .WithOAuthBearerToken(accessToken) - .WithContentType("application/json").WithRequestJson(new RenameHomeScheduleRequest { HomeId = homeId, ScheduleId = scheduleId, Name = name }) - .Times(1); - } - - [Fact] - public async Task SetRoomThermPoint_Should_Return_Expected_Result() - { - var homeId = "5a327cbdb05a2133678b5d3e"; - var roomId = "2255031728"; - var mode = "schedule"; - httpTest.RespondWithJson(new DataResponse { Status = "ok", TimeExec = 0.036107063293457, TimeServer = Instant.FromUnixTimeSeconds(1518023467) }); - - var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); - await sut.SetRoomThermPoint(homeId, roomId, mode); - - httpTest - .ShouldHaveCalled("https://api.netatmo.com/api/setroomthermpoint") - .WithVerb(HttpMethod.Post) - .WithOAuthBearerToken(accessToken) - .WithContentType("application/json").WithRequestJson(new SetRoomThermpointRequest { HomeId = homeId, RoomId = roomId, Mode = mode }) - .Times(1); - } - - [Fact] - public async Task SetThermMode_Should_Return_Expected_Result() - { - var homeId = "5a327cbdb05a2133678b5d3e"; - var mode = "schedule"; - httpTest.RespondWithJson(new DataResponse { Status = "ok", TimeExec = 0.036107063293457, TimeServer = Instant.FromUnixTimeSeconds(1518023467) }); - - var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); - await sut.SetThermMode(homeId, mode); - - httpTest - .ShouldHaveCalled("https://api.netatmo.com/api/setthermmode") - .WithVerb(HttpMethod.Post) - .WithOAuthBearerToken(accessToken) - .WithContentType("application/json").WithRequestJson(new SetThermModeRequest { HomeId = homeId, Mode = mode }) - .Times(1); - } - - [Fact] - public async Task SwitchHomeSchedule_Should_Return_Expected_Result() - { - var homeId = "5a327cbdb05a2133678b5d3e"; - var scheduleId = "5a327cbdb05a2133678b5d3f"; - httpTest.RespondWithJson(new DataResponse { Status = "ok", TimeExec = 0.036107063293457, TimeServer = Instant.FromUnixTimeSeconds(1518023467) }); - - var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); - await sut.SwitchHomeSchedule(homeId, scheduleId); - - httpTest - .ShouldHaveCalled("https://api.netatmo.com/api/switchhomeschedule") - .WithVerb(HttpMethod.Post) - .WithOAuthBearerToken(accessToken) - .WithContentType("application/json").WithRequestJson(new SwitchHomeScheduleRequest { HomeId = homeId, ScheduleId = scheduleId }) - .Times(1); - } - - [Fact] - public async Task SyncHomeSchedule_Should_Return_Expected_Result() - { - var parameters = new SyncHomeScheduleRequest("5a327cbdb05a2133678b5d3e", "5a327cbdb05a2133678b5d3f", 14, 16); - httpTest.RespondWithJson(new DataResponse { Status = "ok", TimeExec = 0.036107063293457, TimeServer = Instant.FromUnixTimeSeconds(1518023467) }); - - var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); - await sut.SyncHomeSchedule(parameters); - - httpTest - .ShouldHaveCalled("https://api.netatmo.com/api/synchomeschedule") - .WithVerb(HttpMethod.Post) - .WithOAuthBearerToken(accessToken) - .WithContentType("application/json") - .WithRequestJson( - new SyncHomeScheduleRequest( - parameters.HomeId, - parameters.ScheduleId, - parameters.HgTemp, - parameters.AwayTemp, - new Timetable[0], - new Zone[0])) - .Times(1); - } - - [Theory] - [ClassData(typeof(GetRoomMeasureArgumentExceptionData))] - public void GetRoomMeasure_Should_Throw_ArgumentException(GetRoomMeasureParameters parameters, string exceptionMessage) - { - var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); - Func act = async () => { await sut.GetRoomMeasure(parameters); }; - - act - .Should().Throw() - .WithMessage(exceptionMessage); - } - } -} \ No newline at end of file diff --git a/src/Netatmo.Tests/WeatherClient.cs b/src/Netatmo.Tests/WeatherClient.cs deleted file mode 100644 index 0252fa3..0000000 --- a/src/Netatmo.Tests/WeatherClient.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Net.Http; -using System.Threading.Tasks; -using FluentAssertions; -using Flurl.Http.Testing; -using Moq; -using Netatmo.Enums; -using Netatmo.Models.Client.Weather; -using Netatmo.Models.Client.Weather.StationsData.DashboardData; -using NodaTime; -using Xunit; - -namespace Netatmo.Tests -{ - public class WeatherClient : IDisposable - { - private readonly HttpTest httpTest; - - public WeatherClient() - { - httpTest = new HttpTest(); - httpTest.Configure(Configuration.ConfigureRequest); - } - - public void Dispose() - { - httpTest.Dispose(); - } - - [Fact] - public async Task GetStationsData_Should_Return_DataResponse_With_StationsData() - { - var accessToken = "Super-Access-Token"; - var credentialManagerMock = new Mock(); - credentialManagerMock.Setup(x => x.AccessToken).Returns(accessToken); - - httpTest.RespondWith( - "{\"body\":{\"devices\":[{\"_id\":\"70:ee:50:2c:xx:xx\",\"last_status_store\":1523889831,\"modules\":[{\"_id\":\"02:00:00:2c:xx:xx\",\"type\":\"NAModule1\",\"last_message\":1523889829,\"last_seen\":1523889816,\"dashboard_data\":{\"Temperature\":24.3,\"temp_trend\":\"stable\",\"Humidity\":40,\"time_utc\":1523889765,\"date_max_temp\":1523885867,\"date_min_temp\":1523851467,\"min_temp\":21.4,\"max_temp\":24.7},\"data_type\":[\"Temperature\",\"Humidity\"],\"module_name\":\"Exterieur\",\"last_setup\":1518622000,\"battery_vp\":5924,\"battery_percent\":97,\"rf_status\":9,\"firmware\":46}],\"place\":{\"altitude\":-55.681362,\"city\":\"Puteaux\",\"country\":\"FR\",\"timezone\":\"Europe\\/Paris\",\"location\":[2.2389,48.8834]},\"station_name\":\"Test\",\"type\":\"NAMain\",\"dashboard_data\":{\"Temperature\":23.7,\"temp_trend\":\"down\",\"Humidity\":42,\"AbsolutePressure\":1033.2,\"Pressure\":1026.4,\"pressure_trend\":\"up\",\"Noise\":53,\"CO2\":1099,\"time_utc\":1523889815,\"date_max_temp\":1523885587,\"date_min_temp\":1523850877,\"min_temp\":21,\"max_temp\":24.4},\"data_type\":[\"Temperature\",\"CO2\",\"Humidity\",\"Noise\",\"Pressure\"],\"co2_calibrating\":false,\"date_setup\":1518621999,\"last_setup\":1518621999,\"module_name\":\"Indoor\",\"firmware\":134,\"last_upgrade\":1518622001,\"wifi_statuswifi_status\":47,\"friend_users\":[\"5a856f288af105312c8xxxxx\"]}],\"user\":{\"mail\":\"example@domain.com\",\"administrative\":{\"lang\":\"fr-FR\",\"reg_locale\":\"en-FR\",\"country\":\"FR\",\"unit\":0,\"windunit\":0,\"pressureunit\":0,\"feel_like_algo\":0}}},\"status\":\"ok\",\"time_exec\":0.075635195,\"time_server\":1523890283}"); - - var sut = new Netatmo.WeatherClient("https://api.netatmo.com/", credentialManagerMock.Object); - var result = await sut.GetStationsData(); - - httpTest - .ShouldHaveCalled("https://api.netatmo.com/api/getstationsdata") - .WithVerb(HttpMethod.Post) - .WithOAuthBearerToken(accessToken) - .WithContentType("application/json").WithRequestJson(new GetStationsDataRequest()) - .Times(1); - - result.Body.Should().BeOfType(); - result.Body.Devices[0].DashboardData.Noise.Should().Be(53); - result.Body.Devices[0].WifiStrength.Should().Be(WifiStrengthEnum.Good); - result.Body.Devices[0].Modules[0].GetDashboardData().HumidityPercent.Should().Be(40); - result.Body.Devices[0].Modules[0] - .Invoking(y => y.GetDashboardData()) - .Should().Throw() - .WithMessage("OutdoorDashBoardData should be expected"); - result.Body.Devices[0].Modules[0].RfStrength.Should().Be(RfStrengthEnum.FullSignal); - result.Body.Devices[0].Modules[0].BatteryStatus.Should().Be(BatteryLevelEnum.Full); - result.Body.Devices[0].Place.Timezone.Should().Be(DateTimeZoneProviders.Tzdb["Europe/Paris"]); - } - } -} \ No newline at end of file diff --git a/src/Netatmo.sln b/src/Netatmo.sln deleted file mode 100644 index 65a6da1..0000000 --- a/src/Netatmo.sln +++ /dev/null @@ -1,28 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Netatmo", "Netatmo\Netatmo.csproj", "{A4B04540-7CF7-4418-ADD7-13BAF1F66538}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Netatmo.Tests", "Netatmo.Tests\Netatmo.Tests.csproj", "{1C2813DA-EB99-4D33-B3AE-20C351D79BC2}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApp", "TestApp\TestApp.csproj", "{4AD37B71-2B90-4F36-960B-5DBEBA956FA4}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A4B04540-7CF7-4418-ADD7-13BAF1F66538}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A4B04540-7CF7-4418-ADD7-13BAF1F66538}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A4B04540-7CF7-4418-ADD7-13BAF1F66538}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A4B04540-7CF7-4418-ADD7-13BAF1F66538}.Release|Any CPU.Build.0 = Release|Any CPU - {1C2813DA-EB99-4D33-B3AE-20C351D79BC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1C2813DA-EB99-4D33-B3AE-20C351D79BC2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1C2813DA-EB99-4D33-B3AE-20C351D79BC2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1C2813DA-EB99-4D33-B3AE-20C351D79BC2}.Release|Any CPU.Build.0 = Release|Any CPU - {4AD37B71-2B90-4F36-960B-5DBEBA956FA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4AD37B71-2B90-4F36-960B-5DBEBA956FA4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4AD37B71-2B90-4F36-960B-5DBEBA956FA4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4AD37B71-2B90-4F36-960B-5DBEBA956FA4}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal diff --git a/src/Netatmo/AirClient.cs b/src/Netatmo/AirClient.cs index 678d27e..d9798cb 100644 --- a/src/Netatmo/AirClient.cs +++ b/src/Netatmo/AirClient.cs @@ -1,33 +1,30 @@ -using System.IO; -using System.Threading.Tasks; using Flurl.Http; using Netatmo.Models.Client; using Netatmo.Models.Client.Air; -namespace Netatmo +namespace Netatmo; + +public class AirClient : IAirClient { - public class AirClient : IAirClient - { - private readonly string baseUrl; - private readonly ICredentialManager credentialManager; + private readonly string baseUrl; + private readonly ICredentialManager credentialManager; - public AirClient(string baseUrl, ICredentialManager credentialManager) - { - this.baseUrl = baseUrl; - this.credentialManager = credentialManager; - } + public AirClient(string baseUrl, ICredentialManager credentialManager) + { + this.baseUrl = baseUrl; + this.credentialManager = credentialManager; + } - public Task> GetHomeCoachsData(string deviceId = null) - { - return baseUrl - .ConfigureRequest(Configuration.ConfigureRequest) - .AppendPathSegment("/api/gethomecoachsdata") - .WithOAuthBearerToken(credentialManager.AccessToken) - .PostJsonAsync(new GetHomeCoachsDataRequest - { - DeviceId = deviceId - }) - .ReceiveJson>(); - } + public Task> GetHomeCoachsData(string deviceId = null) + { + return baseUrl + .ConfigureRequest(Configuration.ConfigureRequest) + .AppendPathSegment("/api/gethomecoachsdata") + .WithOAuthBearerToken(credentialManager.AccessToken) + .PostJsonAsync(new GetHomeCoachsDataRequest + { + DeviceId = deviceId + }) + .ReceiveJson>(); } } \ No newline at end of file diff --git a/src/Netatmo/Client.cs b/src/Netatmo/Client.cs index f9d158a..892eaca 100644 --- a/src/Netatmo/Client.cs +++ b/src/Netatmo/Client.cs @@ -1,43 +1,39 @@ -using System; -using System.Threading.Tasks; -using NodaTime; +using NodaTime; -namespace Netatmo +namespace Netatmo; + +public class Client : IClient { - public class Client : IClient + public Client(IClock clock, string baseUrl, string clientId, string clientSecret) { - public Client(IClock clock, string baseUrl, string clientId, string clientSecret) - { - CredentialManager = new CredentialManager(baseUrl, clientId, clientSecret, clock); - Weather = new WeatherClient(baseUrl, CredentialManager); - Energy = new EnergyClient(baseUrl, CredentialManager); - Air = new AirClient(baseUrl, CredentialManager); - } + CredentialManager = new CredentialManager(baseUrl, clientId, clientSecret, clock); + Weather = new WeatherClient(baseUrl, CredentialManager); + Energy = new EnergyClient(baseUrl, CredentialManager); + Air = new AirClient(baseUrl, CredentialManager); + } - public IWeatherClient Weather { get; } - public IEnergyClient Energy { get; } - public IAirClient Air { get; } - public ICredentialManager CredentialManager { get; } + public IWeatherClient Weather { get; } + public IEnergyClient Energy { get; } + public IAirClient Air { get; } + public ICredentialManager CredentialManager { get; } - public Task GenerateToken(string username, string password, Scope[] scopes = null) - { - Console.WriteLine("Client credentials grant type is deprecated since october 2022 and will not work!"); - return CredentialManager.GenerateToken(username, password, scopes); - } + public Task GenerateToken(string username, string password, Scope[] scopes = null) + { + Console.WriteLine("Client credentials grant type is deprecated since october 2022 and will not work!");return CredentialManager.GenerateToken(username, password, scopes); + } - public void ProvideOAuth2Token(string accessToken) + public void ProvideOAuth2Token(string accessToken) { CredentialManager.ProvideOAuth2Token(accessToken); } public void ProvideOAuth2Token(string accessToken, string refreshToken) - { - CredentialManager.ProvideOAuth2Token(accessToken, refreshToken); - } + { + CredentialManager.ProvideOAuth2Token(accessToken, refreshToken); + } - public Task RefreshToken() - { - return CredentialManager.RefreshToken(); - } + public Task RefreshToken() + { + return CredentialManager.RefreshToken(); } } \ No newline at end of file diff --git a/src/Netatmo/Configuration.cs b/src/Netatmo/Configuration.cs index b83aa65..262e5ab 100644 --- a/src/Netatmo/Configuration.cs +++ b/src/Netatmo/Configuration.cs @@ -1,27 +1,25 @@ -using System.Collections.Generic; using Flurl.Http.Configuration; using Netatmo.Converters; using Newtonsoft.Json; -namespace Netatmo +namespace Netatmo; + +public static class Configuration { - public static class Configuration + public static JsonSerializerSettings JsonSerializer() { - public static JsonSerializerSettings JsonSerializer() + return new JsonSerializerSettings { - return new JsonSerializerSettings - { - NullValueHandling = NullValueHandling.Ignore, - Converters = new List {new TimestampToInstantConverter(), new StringToDateTimeZoneConverter()} - }; - } + NullValueHandling = NullValueHandling.Ignore, + Converters = new List {new TimestampToInstantConverter(), new StringToDateTimeZoneConverter()} + }; + } - public static void ConfigureRequest(FlurlHttpSettings settings) - { - var jsonSettings = JsonSerializer(); + public static void ConfigureRequest(FlurlHttpSettings settings) + { + var jsonSettings = JsonSerializer(); - //jsonSettings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb); - settings.JsonSerializer = new NewtonsoftJsonSerializer(jsonSettings); - } + //jsonSettings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb); + settings.JsonSerializer = new NewtonsoftJsonSerializer(jsonSettings); } } \ No newline at end of file diff --git a/src/Netatmo/Converters/StringToDateTimeZoneConverter.cs b/src/Netatmo/Converters/StringToDateTimeZoneConverter.cs index 58eed76..3749494 100644 --- a/src/Netatmo/Converters/StringToDateTimeZoneConverter.cs +++ b/src/Netatmo/Converters/StringToDateTimeZoneConverter.cs @@ -1,22 +1,20 @@ -using System; using Flurl.Util; using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Converters +namespace Netatmo.Converters; + +public class StringToDateTimeZoneConverter : JsonConverter { - public class StringToDateTimeZoneConverter : JsonConverter + public override void WriteJson(JsonWriter writer, DateTimeZone value, JsonSerializer serializer) { - public override void WriteJson(JsonWriter writer, DateTimeZone value, JsonSerializer serializer) - { - writer.WriteValue(value?.ToInvariantString()); - } + writer.WriteValue(value?.ToInvariantString()); + } - public override DateTimeZone ReadJson(JsonReader reader, Type objectType, DateTimeZone existingValue, bool hasExistingValue, JsonSerializer serializer) - { - if (reader.Value == null) return null; + public override DateTimeZone ReadJson(JsonReader reader, Type objectType, DateTimeZone existingValue, bool hasExistingValue, JsonSerializer serializer) + { + if (reader.Value == null) return null; - return DateTimeZoneProviders.Tzdb[reader.Value.ToString()]; - } + return DateTimeZoneProviders.Tzdb[reader.Value.ToString()]; } } \ No newline at end of file diff --git a/src/Netatmo/Converters/TimestampToInstantConverter.cs b/src/Netatmo/Converters/TimestampToInstantConverter.cs index e139677..3330a75 100644 --- a/src/Netatmo/Converters/TimestampToInstantConverter.cs +++ b/src/Netatmo/Converters/TimestampToInstantConverter.cs @@ -1,23 +1,21 @@ -using System; using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Converters +namespace Netatmo.Converters; + +public class TimestampToInstantConverter : JsonConverter { - public class TimestampToInstantConverter : JsonConverter + public override void WriteJson(JsonWriter writer, Instant? value, JsonSerializer serializer) { - public override void WriteJson(JsonWriter writer, Instant? value, JsonSerializer serializer) - { - if (value.HasValue) writer.WriteValue(value.Value.ToUnixTimeSeconds().ToString()); - } + if (value.HasValue) writer.WriteValue(value.Value.ToUnixTimeSeconds().ToString()); + } - public override Instant? ReadJson(JsonReader reader, Type objectType, Instant? existingValue, bool hasExistingValue, - JsonSerializer serializer) - { - if (reader.Value == null) return null; - var value = long.Parse(reader.Value.ToString()); + public override Instant? ReadJson(JsonReader reader, Type objectType, Instant? existingValue, bool hasExistingValue, + JsonSerializer serializer) + { + if (reader.Value == null) return null; + var value = long.Parse(reader.Value.ToString()); - return Instant.FromUnixTimeSeconds(value); - } + return Instant.FromUnixTimeSeconds(value); } } \ No newline at end of file diff --git a/src/Netatmo/CredentialManager.cs b/src/Netatmo/CredentialManager.cs index 09347a6..a4dd0b0 100644 --- a/src/Netatmo/CredentialManager.cs +++ b/src/Netatmo/CredentialManager.cs @@ -1,80 +1,65 @@ -using System.Linq; -using System.Threading.Tasks; using Flurl; using Flurl.Http; using Netatmo.Models; using Netatmo.Models.Client; using NodaTime; -namespace Netatmo +namespace Netatmo; + +public class CredentialManager : ICredentialManager { - using System; + private readonly string baseUrl; + private readonly string clientId; + private readonly string clientSecret; + private readonly IClock clock; - public class CredentialManager : ICredentialManager + public CredentialManager(string baseUrl, string clientId, string clientSecret, IClock clock) { - private readonly string baseUrl; - private readonly string clientId; - private readonly string clientSecret; - private readonly IClock clock; - - public CredentialManager(string baseUrl, string clientId, string clientSecret, IClock clock) - { - this.baseUrl = baseUrl; - this.clientId = clientId; - this.clientSecret = clientSecret; - this.clock = clock; - } + this.baseUrl = baseUrl; + this.clientId = clientId; + this.clientSecret = clientSecret; + this.clock = clock; + } - public CredentialToken CredentialToken { get; private set; } - public string AccessToken => CredentialToken?.AccessToken; + public CredentialToken CredentialToken { get; private set; } + public string AccessToken => CredentialToken?.AccessToken; - public async Task GenerateToken(string username, string password, Scope[] scopes = null) - { - var scope = string.Join(" ", scopes?.Select(s => s.Value) ?? new string[0]); + public async Task GenerateToken(string username, string password, Scope[] scopes = null) + { + var scope = string.Join(" ", scopes?.Select(s => s.Value) ?? new string[0]); - // TODO : Handle not success status codes (rate limit exceeded, api down, ect) - var token = await baseUrl.AppendPathSegment("/oauth2/token").PostUrlEncodedAsync(new - { - grant_type = "password", - client_id = clientId, - client_secret = clientSecret, - username, - password, - scope - }).ReceiveJson(); + // TODO : Handle not success status codes (rate limit exceeded, api down, ect) + var token = await baseUrl.AppendPathSegment("/oauth2/token") + .PostUrlEncodedAsync( + new + { + grant_type = "password", + client_id = clientId, + client_secret = clientSecret, + username, + password, + scope + }) + .ReceiveJson(); - CredentialToken = new CredentialToken(token, clock); - } + CredentialToken = new CredentialToken(token, clock); + } - public void ProvideOAuth2Token(string accessToken, string refreshToken) - { - var appToken = new Token() - { - AccessToken = accessToken, - RefreshToken = refreshToken, - ExpiresIn = 20 - }; - - CredentialToken = new CredentialToken(appToken, clock); - } + public void ProvideOAuth2Token(string accessToken, string refreshToken) + { + CredentialToken = new CredentialToken(new Token(20, accessToken, refreshToken), clock); + } - public void ProvideOAuth2Token(string accessToken) + public void ProvideOAuth2Token(string accessToken) { ProvideOAuth2Token(accessToken, null); - } - - public async Task RefreshToken() - { - // TODO : Handle not success status codes (rate limit exceeded, api down, ect) - var token = await baseUrl.AppendPathSegment("/oauth2/token").PostUrlEncodedAsync(new - { - grant_type = "refresh_token", - client_id = clientId, - client_secret = clientSecret, - refresh_token = CredentialToken.RefreshToken - }).ReceiveJson(); + }public async Task RefreshToken() + { + // TODO : Handle not success status codes (rate limit exceeded, api down, ect) + var token = await baseUrl.AppendPathSegment("/oauth2/token") + .PostUrlEncodedAsync(new { grant_type = "refresh_token", client_id = clientId, client_secret = clientSecret, refresh_token = CredentialToken.RefreshToken }) + .ReceiveJson(); - CredentialToken = new CredentialToken(token, clock); - } + CredentialToken = new CredentialToken(token, clock); } -} +} \ No newline at end of file diff --git a/src/Netatmo/EnergyClient.cs b/src/Netatmo/EnergyClient.cs index a65568f..b9e95b3 100644 --- a/src/Netatmo/EnergyClient.cs +++ b/src/Netatmo/EnergyClient.cs @@ -1,197 +1,193 @@ -using System; -using System.Linq; -using System.Threading.Tasks; using Flurl.Http; using Netatmo.Models.Client; using Netatmo.Models.Client.Energy; using Netatmo.Models.Client.Energy.RoomMeasure; using NodaTime; -namespace Netatmo +namespace Netatmo; + +public class EnergyClient : IEnergyClient { - public class EnergyClient : IEnergyClient + private readonly string baseUrl; + private readonly ICredentialManager credentialManager; + + public EnergyClient(string baseUrl, ICredentialManager credentialManager) { - private readonly string baseUrl; - private readonly ICredentialManager credentialManager; + this.credentialManager = credentialManager; + this.baseUrl = baseUrl; + } - public EnergyClient(string baseUrl, ICredentialManager credentialManager) - { - this.credentialManager = credentialManager; - this.baseUrl = baseUrl; - } + public Task> GetHomesData(string homeId = null, string gatewayTypes = null) + { + return baseUrl + .ConfigureRequest(Configuration.ConfigureRequest) + .AppendPathSegment("/api/homesdata") + .WithOAuthBearerToken(credentialManager.AccessToken) + .PostJsonAsync(new GetHomesDataRequest + { + HomeId = homeId, + GatewayTypes = gatewayTypes + }) + .ReceiveJson>(); + } - public Task> GetHomesData(string homeId = null, string gatewayTypes = null) - { - return baseUrl - .ConfigureRequest(Configuration.ConfigureRequest) - .AppendPathSegment("/api/homesdata") - .WithOAuthBearerToken(credentialManager.AccessToken) - .PostJsonAsync(new GetHomesDataRequest - { - HomeId = homeId, - GatewayTypes = gatewayTypes - }) - .ReceiveJson>(); - } + public async Task> GetHomeStatus(string homeId, string[] deviceTypes = null) + { + return await baseUrl + .ConfigureRequest(Configuration.ConfigureRequest) + .AppendPathSegment("/api/homestatus") + .WithOAuthBearerToken(credentialManager.AccessToken) + .PostJsonAsync(new GetHomeStatusRequest + { + HomeId = homeId, + DeviceTypes = deviceTypes + }) + .ReceiveJson>(); + } - public async Task> GetHomeStatus(string homeId, string[] deviceTypes = null) - { - return await baseUrl - .ConfigureRequest(Configuration.ConfigureRequest) - .AppendPathSegment("/api/homestatus") - .WithOAuthBearerToken(credentialManager.AccessToken) - .PostJsonAsync(new GetHomeStatusRequest - { - HomeId = homeId, - DeviceTypes = deviceTypes - }) - .ReceiveJson>(); - } + public async Task SetThermMode(string homeId, string mode, Instant? endTime = null) + { + return await baseUrl + .ConfigureRequest(Configuration.ConfigureRequest) + .AppendPathSegment("/api/setthermmode") + .WithOAuthBearerToken(credentialManager.AccessToken) + .PostJsonAsync(new SetThermModeRequest + { + HomeId = homeId, + Mode = mode, + EndTime = endTime + }).ReceiveJson(); + } - public async Task SetThermMode(string homeId, string mode, Instant? endTime = null) - { - return await baseUrl - .ConfigureRequest(Configuration.ConfigureRequest) - .AppendPathSegment("/api/setthermmode") - .WithOAuthBearerToken(credentialManager.AccessToken) - .PostJsonAsync(new SetThermModeRequest - { - HomeId = homeId, - Mode = mode, - EndTime = endTime - }).ReceiveJson(); - } + public async Task SetRoomThermPoint(string homeId, string roomId, string mode, double? temp = null, Instant? endTime = null) + { + return await baseUrl + .ConfigureRequest(Configuration.ConfigureRequest) + .AppendPathSegment("/api/setroomthermpoint") + .WithOAuthBearerToken(credentialManager.AccessToken) + .PostJsonAsync(new SetRoomThermpointRequest + { + HomeId = homeId, + RoomId = roomId, + Mode = mode, + Temp = temp, + EndTime = endTime + }).ReceiveJson(); + } - public async Task SetRoomThermPoint(string homeId, string roomId, string mode, double? temp = null, Instant? endTime = null) - { - return await baseUrl - .ConfigureRequest(Configuration.ConfigureRequest) - .AppendPathSegment("/api/setroomthermpoint") - .WithOAuthBearerToken(credentialManager.AccessToken) - .PostJsonAsync(new SetRoomThermpointRequest - { - HomeId = homeId, - RoomId = roomId, - Mode = mode, - Temp = temp, - EndTime = endTime - }).ReceiveJson(); - } + public async Task> GetRoomMeasure(GetRoomMeasureParameters parameters) where T : IStep + { + ValidateGetRoomMeasureParameters(parameters); - public async Task> GetRoomMeasure(GetRoomMeasureParameters parameters) where T : IStep - { - ValidateGetRoomMeasureParameters(parameters); - - return await baseUrl - .ConfigureRequest(Configuration.ConfigureRequest) - .AppendPathSegment("/api/getroommeasure") - .WithOAuthBearerToken(credentialManager.AccessToken) - .PostJsonAsync(new GetRoomMeasureRequest - { - HomeId = parameters.HomeId, - RoomId = parameters.RoomId, - Scale = parameters.Scale.Value, - Type = parameters.Type.Value, - BeginAt = parameters.BeginAt, - EndAt = parameters.EndAt, - Limit = parameters.Limit, - Optimize = parameters.Optimize, - RealTime = parameters.RealTime - }).ReceiveJson>(); - } + return await baseUrl + .ConfigureRequest(Configuration.ConfigureRequest) + .AppendPathSegment("/api/getroommeasure") + .WithOAuthBearerToken(credentialManager.AccessToken) + .PostJsonAsync(new GetRoomMeasureRequest + { + HomeId = parameters.HomeId, + RoomId = parameters.RoomId, + Scale = parameters.Scale.Value, + Type = parameters.Type.Value, + BeginAt = parameters.BeginAt, + EndAt = parameters.EndAt, + Limit = parameters.Limit, + Optimize = parameters.Optimize, + RealTime = parameters.RealTime + }).ReceiveJson>(); + } - public async Task SwitchHomeSchedule(string homeId, string scheduleId) - { - return await baseUrl - .ConfigureRequest(Configuration.ConfigureRequest) - .AppendPathSegment("/api/switchhomeschedule") - .WithOAuthBearerToken(credentialManager.AccessToken) - .PostJsonAsync(new SwitchHomeScheduleRequest - { - HomeId = homeId, - ScheduleId = scheduleId - }).ReceiveJson(); - } + public async Task SwitchHomeSchedule(string homeId, string scheduleId) + { + return await baseUrl + .ConfigureRequest(Configuration.ConfigureRequest) + .AppendPathSegment("/api/switchhomeschedule") + .WithOAuthBearerToken(credentialManager.AccessToken) + .PostJsonAsync(new SwitchHomeScheduleRequest + { + HomeId = homeId, + ScheduleId = scheduleId + }).ReceiveJson(); + } - public async Task RenameHomeSchedule(string homeId, string scheduleId, string name) - { - return await baseUrl - .ConfigureRequest(Configuration.ConfigureRequest) - .AppendPathSegment("/api/renamehomeschedule") - .WithOAuthBearerToken(credentialManager.AccessToken) - .PostJsonAsync(new RenameHomeScheduleRequest - { - HomeId = homeId, - ScheduleId = scheduleId, - Name = name - }).ReceiveJson(); - } + public async Task RenameHomeSchedule(string homeId, string scheduleId, string name) + { + return await baseUrl + .ConfigureRequest(Configuration.ConfigureRequest) + .AppendPathSegment("/api/renamehomeschedule") + .WithOAuthBearerToken(credentialManager.AccessToken) + .PostJsonAsync(new RenameHomeScheduleRequest + { + HomeId = homeId, + ScheduleId = scheduleId, + Name = name + }).ReceiveJson(); + } - public async Task DeleteHomeSchedule(string homeId, string scheduleId) - { - return await baseUrl - .ConfigureRequest(Configuration.ConfigureRequest) - .AppendPathSegment("/api/deletehomeschedule") - .WithOAuthBearerToken(credentialManager.AccessToken) - .PostJsonAsync(new DeleteHomeScheduleRequest - { - HomeId = homeId, - ScheduleId = scheduleId - }).ReceiveJson(); - } + public async Task DeleteHomeSchedule(string homeId, string scheduleId) + { + return await baseUrl + .ConfigureRequest(Configuration.ConfigureRequest) + .AppendPathSegment("/api/deletehomeschedule") + .WithOAuthBearerToken(credentialManager.AccessToken) + .PostJsonAsync(new DeleteHomeScheduleRequest + { + HomeId = homeId, + ScheduleId = scheduleId + }).ReceiveJson(); + } - public async Task SyncHomeSchedule(SyncHomeScheduleRequest requestParameters) - { - return await baseUrl - .ConfigureRequest(Configuration.ConfigureRequest) - .AppendPathSegment("/api/synchomeschedule") - .WithOAuthBearerToken(credentialManager.AccessToken) - .PostJsonAsync(requestParameters).ReceiveJson(); - } + public async Task SyncHomeSchedule(SyncHomeScheduleRequest requestParameters) + { + return await baseUrl + .ConfigureRequest(Configuration.ConfigureRequest) + .AppendPathSegment("/api/synchomeschedule") + .WithOAuthBearerToken(credentialManager.AccessToken) + .PostJsonAsync(requestParameters).ReceiveJson(); + } - public async Task CreateHomeSchedule(CreateHomeScheduleRequest requestParameters) - { - return await baseUrl - .ConfigureRequest(Configuration.ConfigureRequest) - .AppendPathSegment("/api/createnewhomeschedule") - .WithOAuthBearerToken(credentialManager.AccessToken) - .PostJsonAsync(requestParameters).ReceiveJson(); - } + public async Task CreateHomeSchedule(CreateHomeScheduleRequest requestParameters) + { + return await baseUrl + .ConfigureRequest(Configuration.ConfigureRequest) + .AppendPathSegment("/api/createnewhomeschedule") + .WithOAuthBearerToken(credentialManager.AccessToken) + .PostJsonAsync(requestParameters).ReceiveJson(); + } - private void ValidateGetRoomMeasureParameters(GetRoomMeasureParameters parameters) - { - if (string.IsNullOrWhiteSpace(parameters.HomeId)) - throw new ArgumentException("Home Id shouldn't be null"); + private void ValidateGetRoomMeasureParameters(GetRoomMeasureParameters parameters) + { + if (string.IsNullOrWhiteSpace(parameters.HomeId)) + throw new ArgumentException("Home Id shouldn't be null"); - if (string.IsNullOrWhiteSpace(parameters.RoomId)) - throw new ArgumentException("Room Id shouldn't be null"); + if (string.IsNullOrWhiteSpace(parameters.RoomId)) + throw new ArgumentException("Room Id shouldn't be null"); - if (parameters.Scale == null) - throw new ArgumentException("Scale shouldn't be null"); + if (parameters.Scale == null) + throw new ArgumentException("Scale shouldn't be null"); - if (parameters.Type == null) - throw new ArgumentException("Type shouldn't be null"); + if (parameters.Type == null) + throw new ArgumentException("Type shouldn't be null"); - if (ThermostatMeasurementType.AvailableTypes(parameters.Scale).All(type => type.Value != parameters.Type.Value)) - throw new ArgumentException("Type shouldn't be allow for this scale"); + if (ThermostatMeasurementType.AvailableTypes(parameters.Scale).All(type => type.Value != parameters.Type.Value)) + throw new ArgumentException("Type shouldn't be allow for this scale"); - if (parameters.Limit.HasValue && (parameters.Limit.Value < 0 || parameters.Limit.Value > 1024)) - throw new ArgumentException("Limit should be between 0 and 1024"); + if (parameters.Limit.HasValue && (parameters.Limit.Value < 0 || parameters.Limit.Value > 1024)) + throw new ArgumentException("Limit should be between 0 and 1024"); - if (parameters.BeginAt.HasValue && parameters.EndAt.HasValue && parameters.BeginAt.Value > parameters.EndAt.Value) - throw new ArgumentException("BeginAt should be lower than EndAt"); + if (parameters.BeginAt.HasValue && parameters.EndAt.HasValue && parameters.BeginAt.Value > parameters.EndAt.Value) + throw new ArgumentException("BeginAt should be lower than EndAt"); - if (parameters.Type == ThermostatMeasurementType.Temperature || parameters.Type == ThermostatMeasurementType.SetPointTemperature || - parameters.Type == ThermostatMeasurementType.MinTemp || parameters.Type == ThermostatMeasurementType.MaxTemp) - { - if (typeof(T) != typeof(TemperatureStep)) - throw new ArgumentException("TemperatureStep should be used with a temperature measurement"); - } - else if (parameters.Type == ThermostatMeasurementType.DateMinTemp) - { - if (typeof(T) != typeof(DateTemperatureStep)) - throw new ArgumentException("DateTemperatureStep should be used with a date of temperature measurement"); - } + if (parameters.Type == ThermostatMeasurementType.Temperature || parameters.Type == ThermostatMeasurementType.SetPointTemperature || + parameters.Type == ThermostatMeasurementType.MinTemp || parameters.Type == ThermostatMeasurementType.MaxTemp) + { + if (typeof(T) != typeof(TemperatureStep)) + throw new ArgumentException("TemperatureStep should be used with a temperature measurement"); + } + else if (parameters.Type == ThermostatMeasurementType.DateMinTemp) + { + if (typeof(T) != typeof(DateTemperatureStep)) + throw new ArgumentException("DateTemperatureStep should be used with a date of temperature measurement"); } } } \ No newline at end of file diff --git a/src/Netatmo/Enums/BatteryLevelEnum.cs b/src/Netatmo/Enums/BatteryLevelEnum.cs index 4484a0f..614044d 100644 --- a/src/Netatmo/Enums/BatteryLevelEnum.cs +++ b/src/Netatmo/Enums/BatteryLevelEnum.cs @@ -1,13 +1,12 @@ -namespace Netatmo.Enums +namespace Netatmo.Enums; + +public enum BatteryLevelEnum { - public enum BatteryLevelEnum - { - Undefined = 0, - VeryLow = 1, - Low = 2, - Medium = 3, - High = 4, - Full = 5, - Max = 6 - } + Undefined = 0, + VeryLow = 1, + Low = 2, + Medium = 3, + High = 4, + Full = 5, + Max = 6 } \ No newline at end of file diff --git a/src/Netatmo/Enums/FeelLikeAlgoEnum.cs b/src/Netatmo/Enums/FeelLikeAlgoEnum.cs index 5001528..63e30cc 100644 --- a/src/Netatmo/Enums/FeelLikeAlgoEnum.cs +++ b/src/Netatmo/Enums/FeelLikeAlgoEnum.cs @@ -1,8 +1,7 @@ -namespace Netatmo.Enums +namespace Netatmo.Enums; + +public enum FeelLikeAlgoEnum { - public enum FeelLikeAlgoEnum - { - Humidex = 0, - HeatIndex = 1 - } + Humidex = 0, + HeatIndex = 1 } \ No newline at end of file diff --git a/src/Netatmo/Enums/PressureUnitEnum.cs b/src/Netatmo/Enums/PressureUnitEnum.cs index a132d2b..73b51a5 100644 --- a/src/Netatmo/Enums/PressureUnitEnum.cs +++ b/src/Netatmo/Enums/PressureUnitEnum.cs @@ -1,9 +1,8 @@ -namespace Netatmo.Enums +namespace Netatmo.Enums; + +public enum PressureUnitEnum { - public enum PressureUnitEnum - { - Mbar = 0, - InHg = 1, - MmHg = 2 - } + Mbar = 0, + InHg = 1, + MmHg = 2 } \ No newline at end of file diff --git a/src/Netatmo/Enums/RfStrengthEnum.cs b/src/Netatmo/Enums/RfStrengthEnum.cs index b0e3a30..42825a4 100644 --- a/src/Netatmo/Enums/RfStrengthEnum.cs +++ b/src/Netatmo/Enums/RfStrengthEnum.cs @@ -1,11 +1,10 @@ -namespace Netatmo.Enums +namespace Netatmo.Enums; + +public enum RfStrengthEnum { - public enum RfStrengthEnum - { - Undefined = 0, - Low = 1, - Medium = 2, - High = 3, - FullSignal = 4 - } + Undefined = 0, + Low = 1, + Medium = 2, + High = 3, + FullSignal = 4 } \ No newline at end of file diff --git a/src/Netatmo/Enums/UnitEnum.cs b/src/Netatmo/Enums/UnitEnum.cs index 46f93f8..f2f8224 100644 --- a/src/Netatmo/Enums/UnitEnum.cs +++ b/src/Netatmo/Enums/UnitEnum.cs @@ -1,8 +1,7 @@ -namespace Netatmo.Enums +namespace Netatmo.Enums; + +public enum UnitEnum { - public enum UnitEnum - { - Metric = 0, - Imperial = 1 - } + Metric = 0, + Imperial = 1 } \ No newline at end of file diff --git a/src/Netatmo/Enums/WifiStrengthEnum.cs b/src/Netatmo/Enums/WifiStrengthEnum.cs index a9eee11..1b5958e 100644 --- a/src/Netatmo/Enums/WifiStrengthEnum.cs +++ b/src/Netatmo/Enums/WifiStrengthEnum.cs @@ -1,10 +1,9 @@ -namespace Netatmo.Enums +namespace Netatmo.Enums; + +public enum WifiStrengthEnum { - public enum WifiStrengthEnum - { - Undefined = 0, - Bad = 1, - Average = 2, - Good = 3 - } + Undefined = 0, + Bad = 1, + Average = 2, + Good = 3 } \ No newline at end of file diff --git a/src/Netatmo/Enums/WindUnitEnum.cs b/src/Netatmo/Enums/WindUnitEnum.cs index dba8f6c..67282f3 100644 --- a/src/Netatmo/Enums/WindUnitEnum.cs +++ b/src/Netatmo/Enums/WindUnitEnum.cs @@ -1,11 +1,10 @@ -namespace Netatmo.Enums +namespace Netatmo.Enums; + +public enum WindUnitEnum { - public enum WindUnitEnum - { - Kph = 0, - Mph = 1, - Ms = 2, - Beaufort = 3, - Knot = 4 - } + Kph = 0, + Mph = 1, + Ms = 2, + Beaufort = 3, + Knot = 4 } \ No newline at end of file diff --git a/src/Netatmo/IAirClient.cs b/src/Netatmo/IAirClient.cs index 7615b3f..183dcda 100644 --- a/src/Netatmo/IAirClient.cs +++ b/src/Netatmo/IAirClient.cs @@ -1,11 +1,9 @@ -using System.Threading.Tasks; using Netatmo.Models.Client; using Netatmo.Models.Client.Air; -namespace Netatmo +namespace Netatmo; + +public interface IAirClient { - public interface IAirClient - { - Task> GetHomeCoachsData(string deviceId = null); - } + Task> GetHomeCoachsData(string deviceId = null); } \ No newline at end of file diff --git a/src/Netatmo/IClient.cs b/src/Netatmo/IClient.cs index 6f992be..345a7d4 100644 --- a/src/Netatmo/IClient.cs +++ b/src/Netatmo/IClient.cs @@ -1,15 +1,12 @@ -using System.Threading.Tasks; +namespace Netatmo; -namespace Netatmo +public interface IClient { - public interface IClient - { - IWeatherClient Weather { get; } - IEnergyClient Energy { get; } - IAirClient Air { get; } - ICredentialManager CredentialManager { get; } - Task GenerateToken(string username, string password, Scope[] scopes = null); - void ProvideOAuth2Token(string accessToken); - Task RefreshToken(); - } + IWeatherClient Weather { get; } + IEnergyClient Energy { get; } + IAirClient Air { get; } + ICredentialManager CredentialManager { get; } + Task GenerateToken(string username, string password, Scope[] scopes = null); + void ProvideOAuth2Token(string accessToken); + Task RefreshToken(); } \ No newline at end of file diff --git a/src/Netatmo/ICredentialManager.cs b/src/Netatmo/ICredentialManager.cs index e4b5395..56f22fc 100644 --- a/src/Netatmo/ICredentialManager.cs +++ b/src/Netatmo/ICredentialManager.cs @@ -1,15 +1,13 @@ -using System.Threading.Tasks; using Netatmo.Models; -namespace Netatmo +namespace Netatmo; + +public interface ICredentialManager { - public interface ICredentialManager - { - CredentialToken CredentialToken { get; } - string AccessToken { get; } - Task GenerateToken(string username, string password, Scope[] scopes = null); - void ProvideOAuth2Token(string accessToken); + CredentialToken CredentialToken { get; } + string AccessToken { get; } + Task GenerateToken(string username, string password, Scope[] scopes = null); + void ProvideOAuth2Token(string accessToken); void ProvideOAuth2Token(string accessToken, string refreshToken); - Task RefreshToken(); - } -} + Task RefreshToken(); +} \ No newline at end of file diff --git a/src/Netatmo/IEnergyClient.cs b/src/Netatmo/IEnergyClient.cs index a2f3717..977aa58 100644 --- a/src/Netatmo/IEnergyClient.cs +++ b/src/Netatmo/IEnergyClient.cs @@ -1,22 +1,20 @@ -using System.Threading.Tasks; using Netatmo.Models.Client; using Netatmo.Models.Client.Energy; using Netatmo.Models.Client.Energy.RoomMeasure; using NodaTime; -namespace Netatmo +namespace Netatmo; + +public interface IEnergyClient { - public interface IEnergyClient - { - Task> GetHomesData(string homeId = null, string gatewayTypes = null); - Task> GetHomeStatus(string homeId, string[] deviceTypes = null); - Task SetThermMode(string homeId, string mode, Instant? endTime = null); - Task SetRoomThermPoint(string homeId, string roomId, string mode, double? temp = null, Instant? endTime = null); - Task> GetRoomMeasure(GetRoomMeasureParameters parameters) where T : IStep; - Task SwitchHomeSchedule(string homeId, string scheduleId); - Task RenameHomeSchedule(string homeId, string scheduleId, string name); - Task DeleteHomeSchedule(string homeId, string scheduleId); - Task SyncHomeSchedule(SyncHomeScheduleRequest requestParameters); - Task CreateHomeSchedule(CreateHomeScheduleRequest requestParameters); - } + Task> GetHomesData(string homeId = null, string gatewayTypes = null); + Task> GetHomeStatus(string homeId, string[] deviceTypes = null); + Task SetThermMode(string homeId, string mode, Instant? endTime = null); + Task SetRoomThermPoint(string homeId, string roomId, string mode, double? temp = null, Instant? endTime = null); + Task> GetRoomMeasure(GetRoomMeasureParameters parameters) where T : IStep; + Task SwitchHomeSchedule(string homeId, string scheduleId); + Task RenameHomeSchedule(string homeId, string scheduleId, string name); + Task DeleteHomeSchedule(string homeId, string scheduleId); + Task SyncHomeSchedule(SyncHomeScheduleRequest requestParameters); + Task CreateHomeSchedule(CreateHomeScheduleRequest requestParameters); } \ No newline at end of file diff --git a/src/Netatmo/IWeatherClient.cs b/src/Netatmo/IWeatherClient.cs index ff04a78..62a83a4 100644 --- a/src/Netatmo/IWeatherClient.cs +++ b/src/Netatmo/IWeatherClient.cs @@ -1,11 +1,9 @@ -using System.Threading.Tasks; using Netatmo.Models.Client; using Netatmo.Models.Client.Weather; -namespace Netatmo +namespace Netatmo; + +public interface IWeatherClient { - public interface IWeatherClient - { - Task> GetStationsData(string deviceId = null, bool? onlyFavorites = null); - } + Task> GetStationsData(string deviceId = null, bool? onlyFavorites = null); } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Air/GetHomeCoachsData.cs b/src/Netatmo/Models/Client/Air/GetHomeCoachsData.cs index a58d778..ef6a6a6 100644 --- a/src/Netatmo/Models/Client/Air/GetHomeCoachsData.cs +++ b/src/Netatmo/Models/Client/Air/GetHomeCoachsData.cs @@ -1,14 +1,13 @@ using Netatmo.Models.Client.Air.HomesCoachs; using Newtonsoft.Json; -namespace Netatmo.Models.Client.Air +namespace Netatmo.Models.Client.Air; + +public class GetHomeCoachsData { - public class GetHomeCoachsData - { - [JsonProperty("devices")] - public Devices[] Devices { get; set; } + [JsonProperty("devices")] + public Devices[] Devices { get; set; } - [JsonProperty("user")] - public User User { get; set; } - } + [JsonProperty("user")] + public User User { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Air/GetHomeCoachsDataRequest.cs b/src/Netatmo/Models/Client/Air/GetHomeCoachsDataRequest.cs index b335fdb..bc1ca3a 100644 --- a/src/Netatmo/Models/Client/Air/GetHomeCoachsDataRequest.cs +++ b/src/Netatmo/Models/Client/Air/GetHomeCoachsDataRequest.cs @@ -1,7 +1,6 @@ -namespace Netatmo.Models.Client.Air +namespace Netatmo.Models.Client.Air; + +public class GetHomeCoachsDataRequest { - public class GetHomeCoachsDataRequest - { - public string DeviceId { get; set; } - } + public string DeviceId { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Air/HomesCoachs/DashBoardData.cs b/src/Netatmo/Models/Client/Air/HomesCoachs/DashBoardData.cs index 2a519d8..5b3e083 100644 --- a/src/Netatmo/Models/Client/Air/HomesCoachs/DashBoardData.cs +++ b/src/Netatmo/Models/Client/Air/HomesCoachs/DashBoardData.cs @@ -1,44 +1,43 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client.Air.HomesCoachs +namespace Netatmo.Models.Client.Air.HomesCoachs; + +public class DashBoardData { - public class DashBoardData - { - [JsonProperty("time_utc")] - public Instant TimeUtc { get; set; } + [JsonProperty("time_utc")] + public Instant TimeUtc { get; set; } - [JsonProperty("Temperature")] - public double Temperature { get; set; } + [JsonProperty("Temperature")] + public double Temperature { get; set; } - [JsonProperty("CO2")] - public int CO2 { get; set; } + [JsonProperty("CO2")] + public int CO2 { get; set; } - [JsonProperty("Humidity")] - public int HumidityPercent { get; set; } + [JsonProperty("Humidity")] + public int HumidityPercent { get; set; } - [JsonProperty("Noise")] - public double Noise { get; set; } + [JsonProperty("Noise")] + public double Noise { get; set; } - [JsonProperty("Pressure")] - public double Pressure { get; set; } + [JsonProperty("Pressure")] + public double Pressure { get; set; } - [JsonProperty("AbsolutePressure")] - public double AbsolutePressure { get; set; } + [JsonProperty("AbsolutePressure")] + public double AbsolutePressure { get; set; } - [JsonProperty("health_idx")] - public HealthIdx HealthIdx { get; set; } + [JsonProperty("health_idx")] + public HealthIdx HealthIdx { get; set; } - [JsonProperty("min_temp")] - public decimal MinTemp { get; set; } + [JsonProperty("min_temp")] + public decimal MinTemp { get; set; } - [JsonProperty("max_temp")] - public decimal MaxTemp { get; set; } + [JsonProperty("max_temp")] + public decimal MaxTemp { get; set; } - [JsonProperty("date_min_temp")] - public Instant DateMinTemp { get; set; } + [JsonProperty("date_min_temp")] + public Instant DateMinTemp { get; set; } - [JsonProperty("date_max_temp")] - public Instant DateMaxTemp { get; set; } - } + [JsonProperty("date_max_temp")] + public Instant DateMaxTemp { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Air/HomesCoachs/Devices.cs b/src/Netatmo/Models/Client/Air/HomesCoachs/Devices.cs index 7c35328..dee2893 100644 --- a/src/Netatmo/Models/Client/Air/HomesCoachs/Devices.cs +++ b/src/Netatmo/Models/Client/Air/HomesCoachs/Devices.cs @@ -2,70 +2,67 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client.Air.HomesCoachs +namespace Netatmo.Models.Client.Air.HomesCoachs; + +public class Devices { - public class Devices - { - [JsonProperty("_id")] - public string Id { get; set; } + [JsonProperty("_id")] + public string Id { get; set; } - [JsonProperty("cipher_id")] - public string CipherId { get; set; } + [JsonProperty("cipher_id")] + public string CipherId { get; set; } - [JsonProperty("last_status_store")] - public Instant LastStatusStore { get; set; } + [JsonProperty("last_status_store")] + public Instant LastStatusStore { get; set; } - [JsonProperty("place")] - public Place Place { get; set; } + [JsonProperty("place")] + public Place Place { get; set; } - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("dashboard_data")] - public DashBoardData DashboardData { get; set; } + [JsonProperty("dashboard_data")] + public DashBoardData DashboardData { get; set; } - [JsonProperty("data_type")] - public string[] DataType { get; set; } + [JsonProperty("data_type")] + public string[] DataType { get; set; } - [JsonProperty("co2_calibrating")] - public bool Co2Calibrating { get; set; } + [JsonProperty("co2_calibrating")] + public bool Co2Calibrating { get; set; } - [JsonProperty("reachable")] - public bool Reachable { get; set; } + [JsonProperty("reachable")] + public bool Reachable { get; set; } - [JsonProperty("date_setup")] - public Instant DateSetup { get; set; } + [JsonProperty("date_setup")] + public Instant DateSetup { get; set; } - [JsonProperty("last_setup")] - public Instant LastSetup { get; set; } + [JsonProperty("last_setup")] + public Instant LastSetup { get; set; } - [JsonProperty("module_name")] - public string ModuleName { get; set; } + [JsonProperty("module_name")] + public string ModuleName { get; set; } - [JsonProperty("firmware")] - public int Firmware { get; set; } + [JsonProperty("firmware")] + public int Firmware { get; set; } - [JsonProperty("last_upgrade")] - public Instant LastUpgrade { get; set; } + [JsonProperty("last_upgrade")] + public Instant LastUpgrade { get; set; } - [JsonProperty("station_name")] - public string Name { get; set; } + [JsonProperty("station_name")] + public string Name { get; set; } - [JsonProperty("wifi_status")] - public int WifiStatus { get; set; } + [JsonProperty("wifi_status")] + public int WifiStatus { get; set; } - public WifiStrengthEnum WifiStrength + public WifiStrengthEnum WifiStrength + { + get { - get - { - if (WifiStatus <= 56) return WifiStrengthEnum.Good; - if (WifiStatus <= 71) return WifiStrengthEnum.Average; - return WifiStrengthEnum.Bad; - } + if (WifiStatus <= 56) return WifiStrengthEnum.Good; + if (WifiStatus <= 71) return WifiStrengthEnum.Average; + return WifiStrengthEnum.Bad; } + } - } - - } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Air/HomesCoachs/HealthIdx.cs b/src/Netatmo/Models/Client/Air/HomesCoachs/HealthIdx.cs index b5a1b1e..e41bf02 100644 --- a/src/Netatmo/Models/Client/Air/HomesCoachs/HealthIdx.cs +++ b/src/Netatmo/Models/Client/Air/HomesCoachs/HealthIdx.cs @@ -1,11 +1,10 @@ -namespace Netatmo.Models.Client.Air.HomesCoachs +namespace Netatmo.Models.Client.Air.HomesCoachs; + +public enum HealthIdx { - public enum HealthIdx - { - Healthy = 0, - Fine = 1, - Fair = 2, - Poor = 3, - Unhealthy = 4 - } + Healthy = 0, + Fine = 1, + Fair = 2, + Poor = 3, + Unhealthy = 4 } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/DataResponse.cs b/src/Netatmo/Models/Client/DataResponse.cs index bf4f041..eab712e 100644 --- a/src/Netatmo/Models/Client/DataResponse.cs +++ b/src/Netatmo/Models/Client/DataResponse.cs @@ -1,23 +1,11 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client -{ - public class DataResponse - { - [JsonProperty("status")] - public string Status { get; set; } +namespace Netatmo.Models.Client; - [JsonProperty("time_exec")] - public double? TimeExec { get; set; } +public record DataResponse( + [property: JsonProperty("status")] string Status, + [property: JsonProperty("time_exec")] double? TimeExec, + [property: JsonProperty("time_server")] Instant? TimeServer); - [JsonProperty("time_server")] - public Instant? TimeServer { get; set; } - } - - public class DataResponse : DataResponse - { - [JsonProperty("body")] - public T Body { get; set; } - } -} \ No newline at end of file +public record DataResponse(string Status, double? TimeExec, Instant? TimeServer, [property: JsonProperty("body")] T Body) : DataResponse(Status, TimeExec, TimeServer); \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/CreateHomeScheduleRequest.cs b/src/Netatmo/Models/Client/Energy/CreateHomeScheduleRequest.cs index 2e11f9d..04f98d7 100644 --- a/src/Netatmo/Models/Client/Energy/CreateHomeScheduleRequest.cs +++ b/src/Netatmo/Models/Client/Energy/CreateHomeScheduleRequest.cs @@ -1,46 +1,44 @@ -using System.Collections.Generic; using Newtonsoft.Json; -namespace Netatmo.Models.Client.Energy +namespace Netatmo.Models.Client.Energy; + +public class CreateHomeScheduleRequest { - public class CreateHomeScheduleRequest + public CreateHomeScheduleRequest() { - public CreateHomeScheduleRequest() - { - Timetables = new List(); - Zones = new List(); - } + Timetables = new List(); + Zones = new List(); + } - public CreateHomeScheduleRequest(string homeId, double hgTemp, double awayTemp, string name, Timetable[] timetables = null, - Zone[] zones = null) : - this() - { - HomeId = homeId; - Name = name; - HgTemp = hgTemp; - AwayTemp = awayTemp; + public CreateHomeScheduleRequest(string homeId, double hgTemp, double awayTemp, string name, Timetable[] timetables = null, + Zone[] zones = null) : + this() + { + HomeId = homeId; + Name = name; + HgTemp = hgTemp; + AwayTemp = awayTemp; - if (timetables != null) Timetables.AddRange(timetables); + if (timetables != null) Timetables.AddRange(timetables); - if (zones != null) Zones.AddRange(zones); - } + if (zones != null) Zones.AddRange(zones); + } - [JsonProperty("home_id")] - public string HomeId { get; set; } + [JsonProperty("home_id")] + public string HomeId { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("hg_temp")] - public double HgTemp { get; set; } + [JsonProperty("hg_temp")] + public double HgTemp { get; set; } - [JsonProperty("away_temp")] - public double AwayTemp { get; set; } + [JsonProperty("away_temp")] + public double AwayTemp { get; set; } - [JsonProperty("timetable")] - public List Timetables { get; set; } + [JsonProperty("timetable")] + public List Timetables { get; set; } - [JsonProperty("zones")] - public List Zones { get; set; } - } + [JsonProperty("zones")] + public List Zones { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/CreateHomeScheduleResponse.cs b/src/Netatmo/Models/Client/Energy/CreateHomeScheduleResponse.cs index 466a3f6..00f6169 100644 --- a/src/Netatmo/Models/Client/Energy/CreateHomeScheduleResponse.cs +++ b/src/Netatmo/Models/Client/Energy/CreateHomeScheduleResponse.cs @@ -1,10 +1,7 @@ using Newtonsoft.Json; +using NodaTime; -namespace Netatmo.Models.Client.Energy -{ - public class CreateHomeScheduleResponse : DataResponse - { - [JsonProperty("schedule_id")] - public string ScheduleId { get; set; } - } -} \ No newline at end of file +namespace Netatmo.Models.Client.Energy; + +public record CreateHomeScheduleResponse(string Status, double? TimeExec, Instant? TimeServer, [property: JsonProperty("schedule_id")] string ScheduleId) + : DataResponse(Status, TimeExec, TimeServer); \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/DeleteHomeScheduleRequest.cs b/src/Netatmo/Models/Client/Energy/DeleteHomeScheduleRequest.cs index 38f9808..a2aae6f 100644 --- a/src/Netatmo/Models/Client/Energy/DeleteHomeScheduleRequest.cs +++ b/src/Netatmo/Models/Client/Energy/DeleteHomeScheduleRequest.cs @@ -1,13 +1,12 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Energy +namespace Netatmo.Models.Client.Energy; + +public class DeleteHomeScheduleRequest { - public class DeleteHomeScheduleRequest - { - [JsonProperty("home_id")] - public string HomeId { get; set; } + [JsonProperty("home_id")] + public string HomeId { get; set; } - [JsonProperty("schedule_id")] - public string ScheduleId { get; set; } - } + [JsonProperty("schedule_id")] + public string ScheduleId { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/Enums/ZoneTypeEnum.cs b/src/Netatmo/Models/Client/Energy/Enums/ZoneTypeEnum.cs index 053e2d0..a8e3bf4 100644 --- a/src/Netatmo/Models/Client/Energy/Enums/ZoneTypeEnum.cs +++ b/src/Netatmo/Models/Client/Energy/Enums/ZoneTypeEnum.cs @@ -1,13 +1,12 @@ -namespace Netatmo.Models.Client.Energy.Enums +namespace Netatmo.Models.Client.Energy.Enums; + +public enum ZoneTypeEnum { - public enum ZoneTypeEnum - { - Day = 0, - Night = 1, - Away = 2, - FrostGuard = 3, - Custom = 4, - Eco = 5, - Comfort = 6 - } + Day = 0, + Night = 1, + Away = 2, + FrostGuard = 3, + Custom = 4, + Eco = 5, + Comfort = 6 } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/GetHomeStatusBody.cs b/src/Netatmo/Models/Client/Energy/GetHomeStatusBody.cs index 67d0b1b..110a396 100644 --- a/src/Netatmo/Models/Client/Energy/GetHomeStatusBody.cs +++ b/src/Netatmo/Models/Client/Energy/GetHomeStatusBody.cs @@ -1,11 +1,10 @@ using Netatmo.Models.Client.Energy.HomeStatus; using Newtonsoft.Json; -namespace Netatmo.Models.Client.Energy +namespace Netatmo.Models.Client.Energy; + +public class GetHomeStatusBody { - public class GetHomeStatusBody - { - [JsonProperty("home")] - public Home Home { get; set; } - } + [JsonProperty("home")] + public Home Home { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/GetHomeStatusRequest.cs b/src/Netatmo/Models/Client/Energy/GetHomeStatusRequest.cs index 40f0b27..a9b86cd 100644 --- a/src/Netatmo/Models/Client/Energy/GetHomeStatusRequest.cs +++ b/src/Netatmo/Models/Client/Energy/GetHomeStatusRequest.cs @@ -1,13 +1,12 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Energy +namespace Netatmo.Models.Client.Energy; + +public class GetHomeStatusRequest { - public class GetHomeStatusRequest - { - [JsonProperty("home_id")] - public string HomeId { get; set; } + [JsonProperty("home_id")] + public string HomeId { get; set; } - [JsonProperty("device_types")] - public string[] DeviceTypes { get; set; } - } + [JsonProperty("device_types")] + public string[] DeviceTypes { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/GetHomesDataBody.cs b/src/Netatmo/Models/Client/Energy/GetHomesDataBody.cs index d77e506..1f546fd 100644 --- a/src/Netatmo/Models/Client/Energy/GetHomesDataBody.cs +++ b/src/Netatmo/Models/Client/Energy/GetHomesDataBody.cs @@ -1,14 +1,13 @@ using Netatmo.Models.Client.Energy.HomesData; using Newtonsoft.Json; -namespace Netatmo.Models.Client.Energy +namespace Netatmo.Models.Client.Energy; + +public class GetHomesDataBody { - public class GetHomesDataBody - { - [JsonProperty("homes")] - public Home[] Homes { get; set; } + [JsonProperty("homes")] + public Home[] Homes { get; set; } - [JsonProperty("user")] - public User User { get; set; } - } + [JsonProperty("user")] + public User User { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/GetHomesDataRequest.cs b/src/Netatmo/Models/Client/Energy/GetHomesDataRequest.cs index d628909..48e30b7 100644 --- a/src/Netatmo/Models/Client/Energy/GetHomesDataRequest.cs +++ b/src/Netatmo/Models/Client/Energy/GetHomesDataRequest.cs @@ -1,13 +1,12 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Energy +namespace Netatmo.Models.Client.Energy; + +public class GetHomesDataRequest { - public class GetHomesDataRequest - { - [JsonProperty("home_id")] - public string HomeId { get; set; } + [JsonProperty("home_id")] + public string HomeId { get; set; } - [JsonProperty("gateway_types")] - public string GatewayTypes { get; set; } - } + [JsonProperty("gateway_types")] + public string GatewayTypes { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/GetRoomMeasureParameters.cs b/src/Netatmo/Models/Client/Energy/GetRoomMeasureParameters.cs index f9ac566..64d4cc2 100644 --- a/src/Netatmo/Models/Client/Energy/GetRoomMeasureParameters.cs +++ b/src/Netatmo/Models/Client/Energy/GetRoomMeasureParameters.cs @@ -1,17 +1,16 @@ using NodaTime; -namespace Netatmo.Models.Client.Energy +namespace Netatmo.Models.Client.Energy; + +public class GetRoomMeasureParameters { - public class GetRoomMeasureParameters - { - public string HomeId { get; set; } - public string RoomId { get; set; } - public Scale Scale { get; set; } - public ThermostatMeasurementType Type { get; set; } - public Instant? BeginAt { get; set; } - public Instant? EndAt { get; set; } - public int? Limit { get; set; } - public bool? Optimize { get; set; } - public bool? RealTime { get; set; } - } + public string HomeId { get; set; } + public string RoomId { get; set; } + public Scale Scale { get; set; } + public ThermostatMeasurementType Type { get; set; } + public Instant? BeginAt { get; set; } + public Instant? EndAt { get; set; } + public int? Limit { get; set; } + public bool? Optimize { get; set; } + public bool? RealTime { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/GetRoomMeasureRequest.cs b/src/Netatmo/Models/Client/Energy/GetRoomMeasureRequest.cs index c334d3b..a7457a3 100644 --- a/src/Netatmo/Models/Client/Energy/GetRoomMeasureRequest.cs +++ b/src/Netatmo/Models/Client/Energy/GetRoomMeasureRequest.cs @@ -1,35 +1,34 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client.Energy +namespace Netatmo.Models.Client.Energy; + +public class GetRoomMeasureRequest { - public class GetRoomMeasureRequest - { - [JsonProperty("home_id")] - public string HomeId { get; set; } + [JsonProperty("home_id")] + public string HomeId { get; set; } - [JsonProperty("room_id")] - public string RoomId { get; set; } + [JsonProperty("room_id")] + public string RoomId { get; set; } - [JsonProperty("scale")] - public string Scale { get; set; } + [JsonProperty("scale")] + public string Scale { get; set; } - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("date_begin")] - public Instant? BeginAt { get; set; } + [JsonProperty("date_begin")] + public Instant? BeginAt { get; set; } - [JsonProperty("date_end")] - public Instant? EndAt { get; set; } + [JsonProperty("date_end")] + public Instant? EndAt { get; set; } - [JsonProperty("limit")] - public int? Limit { get; set; } + [JsonProperty("limit")] + public int? Limit { get; set; } - [JsonProperty("optimize")] - public bool? Optimize { get; set; } + [JsonProperty("optimize")] + public bool? Optimize { get; set; } - [JsonProperty("real_time")] - public bool? RealTime { get; set; } - } + [JsonProperty("real_time")] + public bool? RealTime { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/HomeStatus/Home.cs b/src/Netatmo/Models/Client/Energy/HomeStatus/Home.cs index 8b78d7f..d348aec 100644 --- a/src/Netatmo/Models/Client/Energy/HomeStatus/Home.cs +++ b/src/Netatmo/Models/Client/Energy/HomeStatus/Home.cs @@ -1,16 +1,15 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Energy.HomeStatus +namespace Netatmo.Models.Client.Energy.HomeStatus; + +public class Home { - public class Home - { - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("modules")] - public Module[] Modules { get; set; } + [JsonProperty("modules")] + public Module[] Modules { get; set; } - [JsonProperty("rooms")] - public Room[] Rooms { get; set; } - } + [JsonProperty("rooms")] + public Room[] Rooms { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/HomeStatus/Module.cs b/src/Netatmo/Models/Client/Energy/HomeStatus/Module.cs index 22dd548..12f8855 100644 --- a/src/Netatmo/Models/Client/Energy/HomeStatus/Module.cs +++ b/src/Netatmo/Models/Client/Energy/HomeStatus/Module.cs @@ -1,113 +1,112 @@ using Netatmo.Enums; using Newtonsoft.Json; -namespace Netatmo.Models.Client.Energy.HomeStatus +namespace Netatmo.Models.Client.Energy.HomeStatus; + +public class Module { - public class Module - { - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - // NATherm1 = thermostat, NRV = valve, NAPlug = relay, NACamera = welcome camera, NOC = presence camera - [JsonProperty("type")] - public string Type { get; set; } + // NATherm1 = thermostat, NRV = valve, NAPlug = relay, NACamera = welcome camera, NOC = presence camera + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("bridge")] - public string Bridgereachable { get; set; } + [JsonProperty("bridge")] + public string Bridgereachable { get; set; } - // Wifi signal quality : 56 Good, 71 Average, 86 Bad - [JsonProperty("wifi_strength")] - public int? WifiStrength { get; set; } + // Wifi signal quality : 56 Good, 71 Average, 86 Bad + [JsonProperty("wifi_strength")] + public int? WifiStrength { get; set; } - public WifiStrengthEnum WifiStatus + public WifiStrengthEnum WifiStatus + { + get { - get - { - if (!WifiStrength.HasValue) return WifiStrengthEnum.Undefined; + if (!WifiStrength.HasValue) return WifiStrengthEnum.Undefined; - if (WifiStrength.Value <= 56) return WifiStrengthEnum.Good; + if (WifiStrength.Value <= 56) return WifiStrengthEnum.Good; - if (WifiStrength.Value <= 71) return WifiStrengthEnum.Average; + if (WifiStrength.Value <= 71) return WifiStrengthEnum.Average; - return WifiStrengthEnum.Bad; - } + return WifiStrengthEnum.Bad; } + } - // Radio signal quality : 90 = low, 80 = medium, 70 = high, 60 = full signal - [JsonProperty("rf_strength")] - public int RfStrength { get; set; } + // Radio signal quality : 90 = low, 80 = medium, 70 = high, 60 = full signal + [JsonProperty("rf_strength")] + public int RfStrength { get; set; } - public RfStrengthEnum RfStatus + public RfStrengthEnum RfStatus + { + get { - get - { - if (RfStrength <= 60) return RfStrengthEnum.FullSignal; + if (RfStrength <= 60) return RfStrengthEnum.FullSignal; - if (RfStrength <= 70) return RfStrengthEnum.High; + if (RfStrength <= 70) return RfStrengthEnum.High; - if (RfStrength <= 80) return RfStrengthEnum.Medium; + if (RfStrength <= 80) return RfStrengthEnum.Medium; - return RfStrengthEnum.Low; - } + return RfStrengthEnum.Low; } + } - // Only for NATherm1 - [JsonProperty("connected_to_boiler")] - public bool? ConnectedToBoiler { get; set; } + // Only for NATherm1 + [JsonProperty("connected_to_boiler")] + public bool? ConnectedToBoiler { get; set; } - // Only for NATherm1 - [JsonProperty("boiler_status")] - public bool? BoilerStatus { get; set; } + // Only for NATherm1 + [JsonProperty("boiler_status")] + public bool? BoilerStatus { get; set; } - // Only for NATherm1 - [JsonProperty("boiler_valve_comfort_boost")] - public bool? BoilerValveComfortBoost { get; set; } + // Only for NATherm1 + [JsonProperty("boiler_valve_comfort_boost")] + public bool? BoilerValveComfortBoost { get; set; } - [JsonProperty("battery_level")] - public int BatteryLevel { get; set; } + [JsonProperty("battery_level")] + public int BatteryLevel { get; set; } - public BatteryLevelEnum BatteryStatus + public BatteryLevelEnum BatteryStatus + { + get { - get + switch (Type) { - switch (Type) - { - case "NATherm1" when BatteryLevel >= 4100: - return BatteryLevelEnum.Full; - case "NATherm1" when BatteryLevel >= 3600: - return BatteryLevelEnum.High; - case "NATherm1" when BatteryLevel >= 3300: - return BatteryLevelEnum.Medium; - case "NATherm1": - return BatteryLevelEnum.Low; - case "NRV" when BatteryLevel >= 3200: - return BatteryLevelEnum.Full; - case "NRV" when BatteryLevel >= 2700: - return BatteryLevelEnum.High; - case "NRV" when BatteryLevel >= 2400: - return BatteryLevelEnum.Medium; - case "NRV": - return BatteryLevelEnum.Low; - default: - return BatteryLevelEnum.Undefined; - } + case "NATherm1" when BatteryLevel >= 4100: + return BatteryLevelEnum.Full; + case "NATherm1" when BatteryLevel >= 3600: + return BatteryLevelEnum.High; + case "NATherm1" when BatteryLevel >= 3300: + return BatteryLevelEnum.Medium; + case "NATherm1": + return BatteryLevelEnum.Low; + case "NRV" when BatteryLevel >= 3200: + return BatteryLevelEnum.Full; + case "NRV" when BatteryLevel >= 2700: + return BatteryLevelEnum.High; + case "NRV" when BatteryLevel >= 2400: + return BatteryLevelEnum.Medium; + case "NRV": + return BatteryLevelEnum.Low; + default: + return BatteryLevelEnum.Undefined; } } + } - [JsonProperty("battery_state")] - public string BatteryState { get; set; } + [JsonProperty("battery_state")] + public string BatteryState { get; set; } - [JsonProperty("firmware_revision")] - public int FirmwareRevision { get; set; } + [JsonProperty("firmware_revision")] + public int FirmwareRevision { get; set; } - // Only for valve type Number displayed during the pairing with the relay - [JsonProperty("radio_id")] - public int? RadioId { get; set; } + // Only for valve type Number displayed during the pairing with the relay + [JsonProperty("radio_id")] + public int? RadioId { get; set; } - [JsonProperty("anticipating")] - public bool? Anticipating { get; set; } + [JsonProperty("anticipating")] + public bool? Anticipating { get; set; } - [JsonProperty("reachable")] - public bool? Reachable { get; set; } - } + [JsonProperty("reachable")] + public bool? Reachable { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/HomeStatus/Room.cs b/src/Netatmo/Models/Client/Energy/HomeStatus/Room.cs index 8f50586..6f9c89b 100644 --- a/src/Netatmo/Models/Client/Energy/HomeStatus/Room.cs +++ b/src/Netatmo/Models/Client/Energy/HomeStatus/Room.cs @@ -1,38 +1,37 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client.Energy.HomeStatus +namespace Netatmo.Models.Client.Energy.HomeStatus; + +public class Room { - public class Room - { - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("reachable")] - public bool Reachable { get; set; } + [JsonProperty("reachable")] + public bool Reachable { get; set; } - [JsonProperty("anticipating")] - public bool Anticipating { get; set; } + [JsonProperty("anticipating")] + public bool Anticipating { get; set; } - [JsonProperty("open_window")] - public bool OpenWindow { get; set; } + [JsonProperty("open_window")] + public bool OpenWindow { get; set; } - [JsonProperty("therm_measured_temperature")] - public double ThermMeasuredTemperature { get; set; } + [JsonProperty("therm_measured_temperature")] + public double ThermMeasuredTemperature { get; set; } - [JsonProperty("therm_setpoint_temperature")] - public double ThermSetPointTemperature { get; set; } + [JsonProperty("therm_setpoint_temperature")] + public double ThermSetPointTemperature { get; set; } - [JsonProperty("heating_power_request")] - public int? HeatingPowerRequest { get; set; } + [JsonProperty("heating_power_request")] + public int? HeatingPowerRequest { get; set; } - [JsonProperty("therm_setpoint_mode")] - public string ThermSetPointMode { get; set; } + [JsonProperty("therm_setpoint_mode")] + public string ThermSetPointMode { get; set; } - [JsonProperty("therm_setpoint_start_time")] - public Instant ThermSetPointStartTime { get; set; } + [JsonProperty("therm_setpoint_start_time")] + public Instant ThermSetPointStartTime { get; set; } - [JsonProperty("therm_setpoint_end_time")] - public Instant? ThermSetPointEndTime { get; set; } - } + [JsonProperty("therm_setpoint_end_time")] + public Instant? ThermSetPointEndTime { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/HomesData/Home.cs b/src/Netatmo/Models/Client/Energy/HomesData/Home.cs index d7297bb..25b45c7 100644 --- a/src/Netatmo/Models/Client/Energy/HomesData/Home.cs +++ b/src/Netatmo/Models/Client/Energy/HomesData/Home.cs @@ -1,41 +1,40 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client.Energy.HomesData +namespace Netatmo.Models.Client.Energy.HomesData; + +public class Home { - public class Home - { - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("country")] - public string Country { get; set; } + [JsonProperty("country")] + public string Country { get; set; } - [JsonProperty("timezone")] - public DateTimeZone Timezone { get; set; } + [JsonProperty("timezone")] + public DateTimeZone Timezone { get; set; } - [JsonProperty("schedules")] - public Schedule[] Schedules { get; set; } + [JsonProperty("schedules")] + public Schedule[] Schedules { get; set; } - [JsonProperty("coordinates")] - public double[] Coordinates { get; set; } + [JsonProperty("coordinates")] + public double[] Coordinates { get; set; } - [JsonProperty("therm_setpoint_default_duration")] - public int ThermSetpointDefaultDuration { get; set; } + [JsonProperty("therm_setpoint_default_duration")] + public int ThermSetpointDefaultDuration { get; set; } - [JsonProperty("therm_mode")] - public string ThermMode { get; set; } + [JsonProperty("therm_mode")] + public string ThermMode { get; set; } - [JsonProperty("therm_mode_endtime")] - public Instant? ThermModeEndtime { get; set; } + [JsonProperty("therm_mode_endtime")] + public Instant? ThermModeEndtime { get; set; } - [JsonProperty("rooms")] - public Room[] Rooms { get; set; } + [JsonProperty("rooms")] + public Room[] Rooms { get; set; } - [JsonProperty("modules")] - public Module[] Modules { get; set; } - } + [JsonProperty("modules")] + public Module[] Modules { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/HomesData/Module.cs b/src/Netatmo/Models/Client/Energy/HomesData/Module.cs index 589e568..5b6fec0 100644 --- a/src/Netatmo/Models/Client/Energy/HomesData/Module.cs +++ b/src/Netatmo/Models/Client/Energy/HomesData/Module.cs @@ -1,30 +1,29 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client.Energy.HomesData +namespace Netatmo.Models.Client.Energy.HomesData; + +public class Module { - public class Module - { - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - // NATherm1 = thermostat, NRV = valve, NAPlug = relay, NACamera = welcome camera, NOC = presence camera - [JsonProperty("type")] - public string Type { get; set; } + // NATherm1 = thermostat, NRV = valve, NAPlug = relay, NACamera = welcome camera, NOC = presence camera + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("setup_date")] - public Instant SetupAt { get; set; } + [JsonProperty("setup_date")] + public Instant SetupAt { get; set; } - [JsonProperty("modules_bridged")] - public string[] ModulesBridged { get; set; } + [JsonProperty("modules_bridged")] + public string[] ModulesBridged { get; set; } - [JsonProperty("bridge")] - public string Bridge { get; set; } + [JsonProperty("bridge")] + public string Bridge { get; set; } - [JsonProperty("room_id")] - public string RoomId { get; set; } - } + [JsonProperty("room_id")] + public string RoomId { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/HomesData/Room.cs b/src/Netatmo/Models/Client/Energy/HomesData/Room.cs index 792d3f0..f05ba78 100644 --- a/src/Netatmo/Models/Client/Energy/HomesData/Room.cs +++ b/src/Netatmo/Models/Client/Energy/HomesData/Room.cs @@ -1,25 +1,24 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Energy.HomesData +namespace Netatmo.Models.Client.Energy.HomesData; + +public class Room { - public class Room - { - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("measure_offset_NAPlug_estimated_temperature")] - public double MeasureOffsetNaPlugEstimatedTemperature { get; set; } + [JsonProperty("measure_offset_NAPlug_estimated_temperature")] + public double MeasureOffsetNaPlugEstimatedTemperature { get; set; } - [JsonProperty("measure_offset_NAPlug_temperature")] - public double MeasureOffsetNaPlugTemperature { get; set; } + [JsonProperty("measure_offset_NAPlug_temperature")] + public double MeasureOffsetNaPlugTemperature { get; set; } - [JsonProperty("module_ids")] - public string[] ModuleIds { get; set; } - } + [JsonProperty("module_ids")] + public string[] ModuleIds { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/HomesData/Schedule.cs b/src/Netatmo/Models/Client/Energy/HomesData/Schedule.cs index 4d865a0..4b7bca8 100644 --- a/src/Netatmo/Models/Client/Energy/HomesData/Schedule.cs +++ b/src/Netatmo/Models/Client/Energy/HomesData/Schedule.cs @@ -1,33 +1,32 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Energy.HomesData +namespace Netatmo.Models.Client.Energy.HomesData; + +public class Schedule { - public class Schedule - { - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] + public string Type { get; set; } - // Away temperature value - [JsonProperty("away_temp")] - public double AwayTemp { get; set; } + // Away temperature value + [JsonProperty("away_temp")] + public double AwayTemp { get; set; } - // Frostguard temperature value - [JsonProperty("hg_temp")] - public double HgTemp { get; set; } + // Frostguard temperature value + [JsonProperty("hg_temp")] + public double HgTemp { get; set; } - [JsonProperty("selected")] - public bool Selected { get; set; } + [JsonProperty("selected")] + public bool Selected { get; set; } - [JsonProperty("timetables")] - public Timetable[] Timetables { get; set; } + [JsonProperty("timetables")] + public Timetable[] Timetables { get; set; } - [JsonProperty("zones")] - public Zone[] Zones { get; set; } - } + [JsonProperty("zones")] + public Zone[] Zones { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/HomesData/User.cs b/src/Netatmo/Models/Client/Energy/HomesData/User.cs index cb257a7..60059d8 100644 --- a/src/Netatmo/Models/Client/Energy/HomesData/User.cs +++ b/src/Netatmo/Models/Client/Energy/HomesData/User.cs @@ -1,32 +1,31 @@ using Netatmo.Enums; using Newtonsoft.Json; -namespace Netatmo.Models.Client.Energy.HomesData +namespace Netatmo.Models.Client.Energy.HomesData; + +public class User { - public class User - { - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("email")] - public string Email { get; set; } + [JsonProperty("email")] + public string Email { get; set; } - [JsonProperty("language")] - public string Language { get; set; } + [JsonProperty("language")] + public string Language { get; set; } - [JsonProperty("locale")] - public string Locale { get; set; } + [JsonProperty("locale")] + public string Locale { get; set; } - [JsonProperty("feel_like_algorithm")] - public FeelLikeAlgoEnum FeelLikeAlgorithm { get; set; } + [JsonProperty("feel_like_algorithm")] + public FeelLikeAlgoEnum FeelLikeAlgorithm { get; set; } - [JsonProperty("unit_pressure")] - public PressureUnitEnum PressureUnit { get; set; } + [JsonProperty("unit_pressure")] + public PressureUnitEnum PressureUnit { get; set; } - [JsonProperty("unit_system")] - public UnitEnum Unit { get; set; } + [JsonProperty("unit_system")] + public UnitEnum Unit { get; set; } - [JsonProperty("unit_wind")] - public WindUnitEnum WindUnit { get; set; } - } + [JsonProperty("unit_wind")] + public WindUnitEnum WindUnit { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/HomesData/Zone.cs b/src/Netatmo/Models/Client/Energy/HomesData/Zone.cs index 1760bbc..31065ab 100644 --- a/src/Netatmo/Models/Client/Energy/HomesData/Zone.cs +++ b/src/Netatmo/Models/Client/Energy/HomesData/Zone.cs @@ -1,19 +1,18 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Energy.HomesData +namespace Netatmo.Models.Client.Energy.HomesData; + +public class Zone : Energy.Zone { - public class Zone : Energy.Zone - { - [JsonProperty("rooms_temp")] - public RoomTemp[] RoomsTemp { get; set; } + [JsonProperty("rooms_temp")] + public RoomTemp[] RoomsTemp { get; set; } - public class RoomTemp - { - [JsonProperty("room_id")] - public string RoomId { get; set; } + public class RoomTemp + { + [JsonProperty("room_id")] + public string RoomId { get; set; } - [JsonProperty("temp")] - public double Temp { get; set; } - } + [JsonProperty("temp")] + public double Temp { get; set; } } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/RenameHomeScheduleRequest.cs b/src/Netatmo/Models/Client/Energy/RenameHomeScheduleRequest.cs index 5960dc8..5f0edb0 100644 --- a/src/Netatmo/Models/Client/Energy/RenameHomeScheduleRequest.cs +++ b/src/Netatmo/Models/Client/Energy/RenameHomeScheduleRequest.cs @@ -1,16 +1,15 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Energy +namespace Netatmo.Models.Client.Energy; + +public class RenameHomeScheduleRequest { - public class RenameHomeScheduleRequest - { - [JsonProperty("home_id")] - public string HomeId { get; set; } + [JsonProperty("home_id")] + public string HomeId { get; set; } - [JsonProperty("schedule_id")] - public string ScheduleId { get; set; } + [JsonProperty("schedule_id")] + public string ScheduleId { get; set; } - [JsonProperty("name")] - public string Name { get; set; } - } + [JsonProperty("name")] + public string Name { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/RoomMeasure/DateTemperatureStep.cs b/src/Netatmo/Models/Client/Energy/RoomMeasure/DateTemperatureStep.cs index fabc689..98fec93 100644 --- a/src/Netatmo/Models/Client/Energy/RoomMeasure/DateTemperatureStep.cs +++ b/src/Netatmo/Models/Client/Energy/RoomMeasure/DateTemperatureStep.cs @@ -1,8 +1,7 @@ using NodaTime; -namespace Netatmo.Models.Client.Energy.RoomMeasure +namespace Netatmo.Models.Client.Energy.RoomMeasure; + +public class DateTemperatureStep : Step { - public class DateTemperatureStep : Step - { - } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/RoomMeasure/IStep.cs b/src/Netatmo/Models/Client/Energy/RoomMeasure/IStep.cs index e4f41b5..d1aa515 100644 --- a/src/Netatmo/Models/Client/Energy/RoomMeasure/IStep.cs +++ b/src/Netatmo/Models/Client/Energy/RoomMeasure/IStep.cs @@ -1,6 +1,5 @@ -namespace Netatmo.Models.Client.Energy.RoomMeasure +namespace Netatmo.Models.Client.Energy.RoomMeasure; + +public interface IStep { - public interface IStep - { - } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/RoomMeasure/Step.cs b/src/Netatmo/Models/Client/Energy/RoomMeasure/Step.cs index d7ab3aa..ca11f54 100644 --- a/src/Netatmo/Models/Client/Energy/RoomMeasure/Step.cs +++ b/src/Netatmo/Models/Client/Energy/RoomMeasure/Step.cs @@ -1,17 +1,16 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client.Energy.RoomMeasure +namespace Netatmo.Models.Client.Energy.RoomMeasure; + +public abstract class Step : IStep { - public abstract class Step : IStep - { - [JsonProperty("beg_time")] - public Instant BeginAt { get; set; } + [JsonProperty("beg_time")] + public Instant BeginAt { get; set; } - [JsonProperty("step_time")] - public int StepTime { get; set; } + [JsonProperty("step_time")] + public int StepTime { get; set; } - [JsonProperty("value")] - public T[][] Values { get; set; } - } + [JsonProperty("value")] + public T[][] Values { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/RoomMeasure/TemperatureStep.cs b/src/Netatmo/Models/Client/Energy/RoomMeasure/TemperatureStep.cs index 34e1fe2..7b61f6b 100644 --- a/src/Netatmo/Models/Client/Energy/RoomMeasure/TemperatureStep.cs +++ b/src/Netatmo/Models/Client/Energy/RoomMeasure/TemperatureStep.cs @@ -1,6 +1,5 @@ -namespace Netatmo.Models.Client.Energy.RoomMeasure +namespace Netatmo.Models.Client.Energy.RoomMeasure; + +public class TemperatureStep : Step { - public class TemperatureStep : Step - { - } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/SetRoomThermpointRequest.cs b/src/Netatmo/Models/Client/Energy/SetRoomThermpointRequest.cs index 8516429..c930de7 100644 --- a/src/Netatmo/Models/Client/Energy/SetRoomThermpointRequest.cs +++ b/src/Netatmo/Models/Client/Energy/SetRoomThermpointRequest.cs @@ -1,23 +1,22 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client.Energy +namespace Netatmo.Models.Client.Energy; + +public class SetRoomThermpointRequest { - public class SetRoomThermpointRequest - { - [JsonProperty("home_id")] - public string HomeId { get; set; } + [JsonProperty("home_id")] + public string HomeId { get; set; } - [JsonProperty("room_id")] - public string RoomId { get; set; } + [JsonProperty("room_id")] + public string RoomId { get; set; } - [JsonProperty("mode")] - public string Mode { get; set; } + [JsonProperty("mode")] + public string Mode { get; set; } - [JsonProperty("temp")] - public double? Temp { get; set; } + [JsonProperty("temp")] + public double? Temp { get; set; } - [JsonProperty("endtime")] - public Instant? EndTime { get; set; } - } + [JsonProperty("endtime")] + public Instant? EndTime { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/SetThermModeRequest.cs b/src/Netatmo/Models/Client/Energy/SetThermModeRequest.cs index 75de148..871668e 100644 --- a/src/Netatmo/Models/Client/Energy/SetThermModeRequest.cs +++ b/src/Netatmo/Models/Client/Energy/SetThermModeRequest.cs @@ -1,17 +1,16 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client.Energy +namespace Netatmo.Models.Client.Energy; + +public class SetThermModeRequest { - public class SetThermModeRequest - { - [JsonProperty("home_id")] - public string HomeId { get; set; } + [JsonProperty("home_id")] + public string HomeId { get; set; } - [JsonProperty("mode")] - public string Mode { get; set; } + [JsonProperty("mode")] + public string Mode { get; set; } - [JsonProperty("endtime")] - public Instant? EndTime { get; set; } - } + [JsonProperty("endtime")] + public Instant? EndTime { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/SwitchHomeScheduleRequest.cs b/src/Netatmo/Models/Client/Energy/SwitchHomeScheduleRequest.cs index a6af695..c6d13bd 100644 --- a/src/Netatmo/Models/Client/Energy/SwitchHomeScheduleRequest.cs +++ b/src/Netatmo/Models/Client/Energy/SwitchHomeScheduleRequest.cs @@ -1,13 +1,12 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Energy +namespace Netatmo.Models.Client.Energy; + +public class SwitchHomeScheduleRequest { - public class SwitchHomeScheduleRequest - { - [JsonProperty("home_id")] - public string HomeId { get; set; } + [JsonProperty("home_id")] + public string HomeId { get; set; } - [JsonProperty("schedule_id")] - public string ScheduleId { get; set; } - } + [JsonProperty("schedule_id")] + public string ScheduleId { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/SyncHomeScheduleRequest.cs b/src/Netatmo/Models/Client/Energy/SyncHomeScheduleRequest.cs index 25e7c46..a59a4e4 100644 --- a/src/Netatmo/Models/Client/Energy/SyncHomeScheduleRequest.cs +++ b/src/Netatmo/Models/Client/Energy/SyncHomeScheduleRequest.cs @@ -1,60 +1,58 @@ -using System.Collections.Generic; using Newtonsoft.Json; -namespace Netatmo.Models.Client.Energy +namespace Netatmo.Models.Client.Energy; + +public class SyncHomeScheduleRequest { - public class SyncHomeScheduleRequest + public SyncHomeScheduleRequest() { - public SyncHomeScheduleRequest() - { - Timetables = new List(); - Zones = new List(); - } + Timetables = new List(); + Zones = new List(); + } - public SyncHomeScheduleRequest(string homeId, string scheduleId, double hgTemp, double awayTemp, string name = null, - Timetable[] timetables = null, Zone[] zones = null) : - this() - { - HomeId = homeId; - ScheduleId = scheduleId; - Name = name; - HgTemp = hgTemp; - AwayTemp = awayTemp; + public SyncHomeScheduleRequest(string homeId, string scheduleId, double hgTemp, double awayTemp, string name = null, + Timetable[] timetables = null, Zone[] zones = null) : + this() + { + HomeId = homeId; + ScheduleId = scheduleId; + Name = name; + HgTemp = hgTemp; + AwayTemp = awayTemp; - if (timetables != null) Timetables.AddRange(timetables); + if (timetables != null) Timetables.AddRange(timetables); - if (zones != null) Zones.AddRange(zones); - } + if (zones != null) Zones.AddRange(zones); + } - public SyncHomeScheduleRequest(string homeId, string scheduleId, double hgTemp, double awayTemp, string name) : - this(homeId, scheduleId, hgTemp, awayTemp, name, null, null) - { - } + public SyncHomeScheduleRequest(string homeId, string scheduleId, double hgTemp, double awayTemp, string name) : + this(homeId, scheduleId, hgTemp, awayTemp, name, null, null) + { + } - public SyncHomeScheduleRequest(string homeId, string scheduleId, double hgTemp, double awayTemp, Timetable[] timetables, Zone[] zones) : - this(homeId, scheduleId, hgTemp, awayTemp, null, timetables, zones) - { - } + public SyncHomeScheduleRequest(string homeId, string scheduleId, double hgTemp, double awayTemp, Timetable[] timetables, Zone[] zones) : + this(homeId, scheduleId, hgTemp, awayTemp, null, timetables, zones) + { + } - [JsonProperty("home_id")] - public string HomeId { get; set; } + [JsonProperty("home_id")] + public string HomeId { get; set; } - [JsonProperty("schedule_id")] - public string ScheduleId { get; set; } + [JsonProperty("schedule_id")] + public string ScheduleId { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("hg_temp")] - public double HgTemp { get; set; } + [JsonProperty("hg_temp")] + public double HgTemp { get; set; } - [JsonProperty("away_temp")] - public double AwayTemp { get; set; } + [JsonProperty("away_temp")] + public double AwayTemp { get; set; } - [JsonProperty("timetable")] - public List Timetables { get; set; } + [JsonProperty("timetable")] + public List Timetables { get; set; } - [JsonProperty("zones")] - public List Zones { get; set; } - } + [JsonProperty("zones")] + public List Zones { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/Timetable.cs b/src/Netatmo/Models/Client/Energy/Timetable.cs index 97c2919..5380d2f 100644 --- a/src/Netatmo/Models/Client/Energy/Timetable.cs +++ b/src/Netatmo/Models/Client/Energy/Timetable.cs @@ -1,24 +1,23 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Energy +namespace Netatmo.Models.Client.Energy; + +public class Timetable { - public class Timetable + public Timetable() { - public Timetable() - { - } + } - public Timetable(string zoneId, int mOffset) - { - ZoneId = zoneId; - MOffset = mOffset; - } + public Timetable(string zoneId, int mOffset) + { + ZoneId = zoneId; + MOffset = mOffset; + } - [JsonProperty("id")] - public string ZoneId { get; set; } + [JsonProperty("id")] + public string ZoneId { get; set; } - // offset in minutes since Monday 00:00:01 - [JsonProperty("m_offset")] - public int MOffset { get; set; } - } + // offset in minutes since Monday 00:00:01 + [JsonProperty("m_offset")] + public int MOffset { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Energy/Zone.cs b/src/Netatmo/Models/Client/Energy/Zone.cs index b718886..52662ca 100644 --- a/src/Netatmo/Models/Client/Energy/Zone.cs +++ b/src/Netatmo/Models/Client/Energy/Zone.cs @@ -1,55 +1,53 @@ -using System.Collections.Generic; using Netatmo.Models.Client.Energy.Enums; using Newtonsoft.Json; -namespace Netatmo.Models.Client.Energy +namespace Netatmo.Models.Client.Energy; + +public class Zone { - public class Zone + public Zone() { - public Zone() - { - Rooms = new List(); - } + Rooms = new List(); + } - public Zone(string id, string name, ZoneTypeEnum type, Room[] rooms = null) : - this() - { - Id = id; - Name = name; - Type = type; + public Zone(string id, string name, ZoneTypeEnum type, Room[] rooms = null) : + this() + { + Id = id; + Name = name; + Type = type; - if (rooms != null) Rooms.AddRange(rooms); - } + if (rooms != null) Rooms.AddRange(rooms); + } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("type")] - public ZoneTypeEnum Type { get; set; } + [JsonProperty("type")] + public ZoneTypeEnum Type { get; set; } - [JsonProperty("rooms")] - public List Rooms { get; set; } + [JsonProperty("rooms")] + public List Rooms { get; set; } - public class Room + public class Room + { + public Room() { - public Room() - { - } + } - public Room(string id, double thermSetPointTemperature) - { - Id = id; - ThermSetPointTemperature = thermSetPointTemperature; - } + public Room(string id, double thermSetPointTemperature) + { + Id = id; + ThermSetPointTemperature = thermSetPointTemperature; + } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("therm_setpoint_temperature")] - public double ThermSetPointTemperature { get; set; } - } + [JsonProperty("therm_setpoint_temperature")] + public double ThermSetPointTemperature { get; set; } } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Place.cs b/src/Netatmo/Models/Client/Place.cs index 9bf82a8..291fe38 100644 --- a/src/Netatmo/Models/Client/Place.cs +++ b/src/Netatmo/Models/Client/Place.cs @@ -1,23 +1,11 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client -{ - public class Place - { - [JsonProperty("altitude")] - public double Altitude { get; set; } - - [JsonProperty("city")] - public string City { get; set; } - - [JsonProperty("country")] - public string Country { get; set; } - - [JsonProperty("timezone")] - public DateTimeZone Timezone { get; set; } - - [JsonProperty("location")] - public double[] Location { get; set; } - } -} \ No newline at end of file +namespace Netatmo.Models.Client; + +public record Place( + [property: JsonProperty("altitude")] double Altitude, + [property: JsonProperty("city")] string City, + [property: JsonProperty("country")] string Country, + [property: JsonProperty("timezone")] DateTimeZone Timezone, + [property: JsonProperty("location")] double[] Location); \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Token.cs b/src/Netatmo/Models/Client/Token.cs index a6e9d7f..8d7b3de 100644 --- a/src/Netatmo/Models/Client/Token.cs +++ b/src/Netatmo/Models/Client/Token.cs @@ -1,16 +1,8 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client -{ - public class Token - { - [JsonProperty("expires_in")] - public int ExpiresIn { get; set; } +namespace Netatmo.Models.Client; - [JsonProperty("access_token")] - public string AccessToken { get; set; } - - [JsonProperty("refresh_token")] - public string RefreshToken { get; set; } - } -} \ No newline at end of file +public record Token( + [property: JsonProperty("expires_in")] int ExpiresIn, + [property: JsonProperty("access_token")] string AccessToken, + [property: JsonProperty("refresh_token")] string RefreshToken); \ No newline at end of file diff --git a/src/Netatmo/Models/Client/User.cs b/src/Netatmo/Models/Client/User.cs index 41b3611..93efee9 100644 --- a/src/Netatmo/Models/Client/User.cs +++ b/src/Netatmo/Models/Client/User.cs @@ -1,14 +1,6 @@ using Netatmo.Models.Client.Weather.StationsData; using Newtonsoft.Json; -namespace Netatmo.Models.Client -{ - public class User - { - [JsonProperty("administrative")] - public Administrative Administrative { get; set; } +namespace Netatmo.Models.Client; - [JsonProperty("mail")] - public string Mail { get; set; } - } -} \ No newline at end of file +public record User([property: JsonProperty("administrative")] Administrative Administrative, [property: JsonProperty("mail")] string Mail); \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/GetStationsDataBody.cs b/src/Netatmo/Models/Client/Weather/GetStationsDataBody.cs index e522dd0..276aabe 100644 --- a/src/Netatmo/Models/Client/Weather/GetStationsDataBody.cs +++ b/src/Netatmo/Models/Client/Weather/GetStationsDataBody.cs @@ -1,14 +1,13 @@ using Netatmo.Models.Client.Weather.StationsData; using Newtonsoft.Json; -namespace Netatmo.Models.Client.Weather +namespace Netatmo.Models.Client.Weather; + +public class GetStationsDataBody { - public class GetStationsDataBody - { - [JsonProperty("devices")] - public Device[] Devices { get; set; } + [JsonProperty("devices")] + public Device[] Devices { get; set; } - [JsonProperty("user")] - public User User { get; set; } - } + [JsonProperty("user")] + public User User { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/GetStationsDataRequest.cs b/src/Netatmo/Models/Client/Weather/GetStationsDataRequest.cs index d745ae0..416b2bf 100644 --- a/src/Netatmo/Models/Client/Weather/GetStationsDataRequest.cs +++ b/src/Netatmo/Models/Client/Weather/GetStationsDataRequest.cs @@ -1,13 +1,12 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Weather +namespace Netatmo.Models.Client.Weather; + +public class GetStationsDataRequest { - public class GetStationsDataRequest - { - [JsonProperty("device_id")] - public string DeviceId { get; set; } + [JsonProperty("device_id")] + public string DeviceId { get; set; } - [JsonProperty("get_favorites")] - public bool? GetFavorites { get; set; } - } + [JsonProperty("get_favorites")] + public bool? GetFavorites { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/Administrative.cs b/src/Netatmo/Models/Client/Weather/StationsData/Administrative.cs index c891c45..e483ded 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/Administrative.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/Administrative.cs @@ -1,29 +1,28 @@ using Netatmo.Enums; using Newtonsoft.Json; -namespace Netatmo.Models.Client.Weather.StationsData +namespace Netatmo.Models.Client.Weather.StationsData; + +public class Administrative { - public class Administrative - { - [JsonProperty("country")] - public string Country { get; set; } + [JsonProperty("country")] + public string Country { get; set; } - [JsonProperty("feel_like_algo")] - public FeelLikeAlgoEnum FeelLikeAlgo { get; set; } + [JsonProperty("feel_like_algo")] + public FeelLikeAlgoEnum FeelLikeAlgo { get; set; } - [JsonProperty("lang")] - public string Lang { get; set; } + [JsonProperty("lang")] + public string Lang { get; set; } - [JsonProperty("pressureunit")] - public PressureUnitEnum PressureUnit { get; set; } + [JsonProperty("pressureunit")] + public PressureUnitEnum PressureUnit { get; set; } - [JsonProperty("reg_locale")] - public string RegLocale { get; set; } + [JsonProperty("reg_locale")] + public string RegLocale { get; set; } - [JsonProperty("unit")] - public UnitEnum Unit { get; set; } + [JsonProperty("unit")] + public UnitEnum Unit { get; set; } - [JsonProperty("windunit")] - public WindUnitEnum WindUnit { get; set; } - } + [JsonProperty("windunit")] + public WindUnitEnum WindUnit { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/BaseStationDashBoardData.cs b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/BaseStationDashBoardData.cs index 7b23d4f..92f7cab 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/BaseStationDashBoardData.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/BaseStationDashBoardData.cs @@ -1,47 +1,46 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client.Weather.StationsData.DashboardData +namespace Netatmo.Models.Client.Weather.StationsData.DashboardData; + +public class BaseStationDashBoardData : DashBoardData, ICO2DashBoardData, IHumidityDashBoardData, ITemperatureDashBoardData, + INoiseDashBoardData, IPressureDashBoardData { - public class BaseStationDashBoardData : DashBoardData, ICO2DashBoardData, IHumidityDashBoardData, ITemperatureDashBoardData, - INoiseDashBoardData, IPressureDashBoardData - { - [JsonProperty("CO2")] - public int CO2 { get; set; } + [JsonProperty("CO2")] + public int CO2 { get; set; } - [JsonProperty("Humidity")] - public int HumidityPercent { get; set; } + [JsonProperty("Humidity")] + public int HumidityPercent { get; set; } - [JsonProperty("Noise")] - public double Noise { get; set; } + [JsonProperty("Noise")] + public double Noise { get; set; } - [JsonProperty("AbsolutePressure")] - public double AbsolutePressure { get; set; } + [JsonProperty("AbsolutePressure")] + public double AbsolutePressure { get; set; } - [JsonProperty("Pressure")] - public double Pressure { get; set; } + [JsonProperty("Pressure")] + public double Pressure { get; set; } - // pressure_trend for last 12h (up, down, stable) - [JsonProperty("pressure_trend")] - public string PressureTrend { get; set; } + // pressure_trend for last 12h (up, down, stable) + [JsonProperty("pressure_trend")] + public string PressureTrend { get; set; } - [JsonProperty("Temperature")] - public double Temperature { get; set; } + [JsonProperty("Temperature")] + public double Temperature { get; set; } - // temp_trend for last 12h (up, down, stable) - [JsonProperty("temp_trend")] - public string TempTrend { get; set; } + // temp_trend for last 12h (up, down, stable) + [JsonProperty("temp_trend")] + public string TempTrend { get; set; } - [JsonProperty("min_temp")] - public double MinTemp { get; set; } + [JsonProperty("min_temp")] + public double MinTemp { get; set; } - [JsonProperty("max_temp")] - public double MaxTemp { get; set; } + [JsonProperty("max_temp")] + public double MaxTemp { get; set; } - [JsonProperty("date_min_temp")] - public Instant MinTempAt { get; set; } + [JsonProperty("date_min_temp")] + public Instant MinTempAt { get; set; } - [JsonProperty("date_max_temp")] - public Instant MaxTempAt { get; set; } - } + [JsonProperty("date_max_temp")] + public Instant MaxTempAt { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/DashBoardData.cs b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/DashBoardData.cs index f2f7bd6..47385b0 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/DashBoardData.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/DashBoardData.cs @@ -1,11 +1,10 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client.Weather.StationsData.DashboardData +namespace Netatmo.Models.Client.Weather.StationsData.DashboardData; + +public class DashBoardData : IDashBoardData { - public class DashBoardData : IDashBoardData - { - [JsonProperty("time_utc")] - public Instant TimeUtc { get; set; } - } + [JsonProperty("time_utc")] + public Instant TimeUtc { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/ICO2DashBoardData.cs b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/ICO2DashBoardData.cs index 689f4dd..4067d7d 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/ICO2DashBoardData.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/ICO2DashBoardData.cs @@ -1,10 +1,9 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Weather.StationsData.DashboardData +namespace Netatmo.Models.Client.Weather.StationsData.DashboardData; + +public interface ICO2DashBoardData : IDashBoardData { - public interface ICO2DashBoardData : IDashBoardData - { - [JsonProperty("CO2")] - int CO2 { get; set; } - } + [JsonProperty("CO2")] + int CO2 { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IDashBoardData.cs b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IDashBoardData.cs index 88850c7..664efa3 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IDashBoardData.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IDashBoardData.cs @@ -1,11 +1,10 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client.Weather.StationsData.DashboardData +namespace Netatmo.Models.Client.Weather.StationsData.DashboardData; + +public interface IDashBoardData { - public interface IDashBoardData - { - [JsonProperty("time_utc")] - Instant TimeUtc { get; set; } - } + [JsonProperty("time_utc")] + Instant TimeUtc { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IGustDashBoardData.cs b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IGustDashBoardData.cs index d23f07a..4f6b02b 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IGustDashBoardData.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IGustDashBoardData.cs @@ -1,13 +1,12 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Weather.StationsData.DashboardData +namespace Netatmo.Models.Client.Weather.StationsData.DashboardData; + +public interface IGustDashBoardData : IDashBoardData { - public interface IGustDashBoardData : IDashBoardData - { - [JsonProperty("GustStrength")] - int GustStrength { get; set; } + [JsonProperty("GustStrength")] + int GustStrength { get; set; } - [JsonProperty("GustAngle")] - int GustAngle { get; set; } - } + [JsonProperty("GustAngle")] + int GustAngle { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IHumidityDashBoardData.cs b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IHumidityDashBoardData.cs index c6789d7..c144c54 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IHumidityDashBoardData.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IHumidityDashBoardData.cs @@ -1,10 +1,9 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Weather.StationsData.DashboardData +namespace Netatmo.Models.Client.Weather.StationsData.DashboardData; + +public interface IHumidityDashBoardData : IDashBoardData { - public interface IHumidityDashBoardData : IDashBoardData - { - [JsonProperty("Humidity")] - int HumidityPercent { get; set; } - } + [JsonProperty("Humidity")] + int HumidityPercent { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/INoiseDashBoardData.cs b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/INoiseDashBoardData.cs index 6c20dcb..69a5aa3 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/INoiseDashBoardData.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/INoiseDashBoardData.cs @@ -1,10 +1,9 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Weather.StationsData.DashboardData +namespace Netatmo.Models.Client.Weather.StationsData.DashboardData; + +public interface INoiseDashBoardData : IDashBoardData { - public interface INoiseDashBoardData : IDashBoardData - { - [JsonProperty("Noise")] - double Noise { get; set; } - } + [JsonProperty("Noise")] + double Noise { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IPressureDashBoardData.cs b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IPressureDashBoardData.cs index 2392944..708d9f9 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IPressureDashBoardData.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IPressureDashBoardData.cs @@ -1,17 +1,16 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Weather.StationsData.DashboardData +namespace Netatmo.Models.Client.Weather.StationsData.DashboardData; + +public interface IPressureDashBoardData : IDashBoardData { - public interface IPressureDashBoardData : IDashBoardData - { - [JsonProperty("AbsolutePressure")] - double AbsolutePressure { get; set; } + [JsonProperty("AbsolutePressure")] + double AbsolutePressure { get; set; } - [JsonProperty("Pressure")] - double Pressure { get; set; } + [JsonProperty("Pressure")] + double Pressure { get; set; } - // pressure_trend for last 12h (up, down, stable) - [JsonProperty("pressure_trend")] - string PressureTrend { get; set; } - } + // pressure_trend for last 12h (up, down, stable) + [JsonProperty("pressure_trend")] + string PressureTrend { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IRainDashBoardData.cs b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IRainDashBoardData.cs index cf85bd3..f8433b1 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IRainDashBoardData.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IRainDashBoardData.cs @@ -1,16 +1,15 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Weather.StationsData.DashboardData +namespace Netatmo.Models.Client.Weather.StationsData.DashboardData; + +public interface IRainDashBoardData : IDashBoardData { - public interface IRainDashBoardData : IDashBoardData - { - [JsonProperty("Rain")] - double Rain { get; set; } + [JsonProperty("Rain")] + double Rain { get; set; } - [JsonProperty("sum_rain_1")] - double RainLastHour { get; set; } + [JsonProperty("sum_rain_1")] + double RainLastHour { get; set; } - [JsonProperty("sum_rain_24")] - double RainLastDay { get; set; } - } + [JsonProperty("sum_rain_24")] + double RainLastDay { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/ITemperatureDashBoardData.cs b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/ITemperatureDashBoardData.cs index dde7014..96db992 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/ITemperatureDashBoardData.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/ITemperatureDashBoardData.cs @@ -1,27 +1,26 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client.Weather.StationsData.DashboardData +namespace Netatmo.Models.Client.Weather.StationsData.DashboardData; + +public interface ITemperatureDashBoardData : IDashBoardData { - public interface ITemperatureDashBoardData : IDashBoardData - { - [JsonProperty("Temperature")] - double Temperature { get; set; } + [JsonProperty("Temperature")] + double Temperature { get; set; } - // temp_trend for last 12h (up, down, stable) - [JsonProperty("temp_trend")] - string TempTrend { get; set; } + // temp_trend for last 12h (up, down, stable) + [JsonProperty("temp_trend")] + string TempTrend { get; set; } - [JsonProperty("min_temp")] - double MinTemp { get; set; } + [JsonProperty("min_temp")] + double MinTemp { get; set; } - [JsonProperty("max_temp")] - double MaxTemp { get; set; } + [JsonProperty("max_temp")] + double MaxTemp { get; set; } - [JsonProperty("date_min_temp")] - Instant MinTempAt { get; set; } + [JsonProperty("date_min_temp")] + Instant MinTempAt { get; set; } - [JsonProperty("date_max_temp")] - Instant MaxTempAt { get; set; } - } + [JsonProperty("date_max_temp")] + Instant MaxTempAt { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IWindDashBoardData.cs b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IWindDashBoardData.cs index 4a57eb8..5eb942c 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IWindDashBoardData.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IWindDashBoardData.cs @@ -1,18 +1,17 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Weather.StationsData.DashboardData +namespace Netatmo.Models.Client.Weather.StationsData.DashboardData; + +public interface IWindHistory : IDashBoardData { - public interface IWindHistory : IDashBoardData - { - [JsonProperty("WindStrength")] - int WindStrength { get; set; } + [JsonProperty("WindStrength")] + int WindStrength { get; set; } - [JsonProperty("WindAngle")] - int WindAngle { get; set; } - } + [JsonProperty("WindAngle")] + int WindAngle { get; set; } +} - public interface IWindDashBoardData : IWindHistory - { - WindHistoric[] WindHistoric { get; set; } - } +public interface IWindDashBoardData : IWindHistory +{ + WindHistoric[] WindHistoric { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IndoorDashBoardData.cs b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IndoorDashBoardData.cs index 1cb70ad..8d7cc40 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IndoorDashBoardData.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/IndoorDashBoardData.cs @@ -1,33 +1,32 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client.Weather.StationsData.DashboardData +namespace Netatmo.Models.Client.Weather.StationsData.DashboardData; + +public class IndoorDashBoardData : DashBoardData, ITemperatureDashBoardData, ICO2DashBoardData, IHumidityDashBoardData { - public class IndoorDashBoardData : DashBoardData, ITemperatureDashBoardData, ICO2DashBoardData, IHumidityDashBoardData - { - [JsonProperty("CO2")] - public int CO2 { get; set; } + [JsonProperty("CO2")] + public int CO2 { get; set; } - [JsonProperty("Humidity")] - public int HumidityPercent { get; set; } + [JsonProperty("Humidity")] + public int HumidityPercent { get; set; } - [JsonProperty("Temperature")] - public double Temperature { get; set; } + [JsonProperty("Temperature")] + public double Temperature { get; set; } - // temp_trend for last 12h (up, down, stable) - [JsonProperty("temp_trend")] - public string TempTrend { get; set; } + // temp_trend for last 12h (up, down, stable) + [JsonProperty("temp_trend")] + public string TempTrend { get; set; } - [JsonProperty("min_temp")] - public double MinTemp { get; set; } + [JsonProperty("min_temp")] + public double MinTemp { get; set; } - [JsonProperty("max_temp")] - public double MaxTemp { get; set; } + [JsonProperty("max_temp")] + public double MaxTemp { get; set; } - [JsonProperty("date_min_temp")] - public Instant MinTempAt { get; set; } + [JsonProperty("date_min_temp")] + public Instant MinTempAt { get; set; } - [JsonProperty("date_max_temp")] - public Instant MaxTempAt { get; set; } - } + [JsonProperty("date_max_temp")] + public Instant MaxTempAt { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/OutdoorDashBoardData.cs b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/OutdoorDashBoardData.cs index 746609a..9fc6cea 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/OutdoorDashBoardData.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/OutdoorDashBoardData.cs @@ -1,30 +1,29 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client.Weather.StationsData.DashboardData +namespace Netatmo.Models.Client.Weather.StationsData.DashboardData; + +public class OutdoorDashBoardData : DashBoardData, ITemperatureDashBoardData, IHumidityDashBoardData { - public class OutdoorDashBoardData : DashBoardData, ITemperatureDashBoardData, IHumidityDashBoardData - { - [JsonProperty("Humidity")] - public int HumidityPercent { get; set; } + [JsonProperty("Humidity")] + public int HumidityPercent { get; set; } - [JsonProperty("Temperature")] - public double Temperature { get; set; } + [JsonProperty("Temperature")] + public double Temperature { get; set; } - // temp_trend for last 12h (up, down, stable) - [JsonProperty("temp_trend")] - public string TempTrend { get; set; } + // temp_trend for last 12h (up, down, stable) + [JsonProperty("temp_trend")] + public string TempTrend { get; set; } - [JsonProperty("min_temp")] - public double MinTemp { get; set; } + [JsonProperty("min_temp")] + public double MinTemp { get; set; } - [JsonProperty("max_temp")] - public double MaxTemp { get; set; } + [JsonProperty("max_temp")] + public double MaxTemp { get; set; } - [JsonProperty("date_min_temp")] - public Instant MinTempAt { get; set; } + [JsonProperty("date_min_temp")] + public Instant MinTempAt { get; set; } - [JsonProperty("date_max_temp")] - public Instant MaxTempAt { get; set; } - } + [JsonProperty("date_max_temp")] + public Instant MaxTempAt { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/RainGaugeDashBoardData.cs b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/RainGaugeDashBoardData.cs index e40c07e..6d3747a 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/RainGaugeDashBoardData.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/RainGaugeDashBoardData.cs @@ -1,16 +1,15 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Weather.StationsData.DashboardData +namespace Netatmo.Models.Client.Weather.StationsData.DashboardData; + +public class RainGaugeDashBoardData : DashBoardData, IRainDashBoardData { - public class RainGaugeDashBoardData : DashBoardData, IRainDashBoardData - { - [JsonProperty("Rain")] - public double Rain { get; set; } + [JsonProperty("Rain")] + public double Rain { get; set; } - [JsonProperty("sum_rain_1")] - public double RainLastHour { get; set; } + [JsonProperty("sum_rain_1")] + public double RainLastHour { get; set; } - [JsonProperty("sum_rain_24")] - public double RainLastDay { get; set; } - } + [JsonProperty("sum_rain_24")] + public double RainLastDay { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/WindGaugeDashBoardData.cs b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/WindGaugeDashBoardData.cs index b7a549a..f901aac 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/WindGaugeDashBoardData.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/WindGaugeDashBoardData.cs @@ -1,22 +1,21 @@ using Newtonsoft.Json; -namespace Netatmo.Models.Client.Weather.StationsData.DashboardData +namespace Netatmo.Models.Client.Weather.StationsData.DashboardData; + +public class WindGaugeDashBoardData : DashBoardData, IWindDashBoardData, IGustDashBoardData { - public class WindGaugeDashBoardData : DashBoardData, IWindDashBoardData, IGustDashBoardData - { - [JsonProperty("WindHistoric")] - public WindHistoric[] WindHistoric { get; set; } + [JsonProperty("WindHistoric")] + public WindHistoric[] WindHistoric { get; set; } - [JsonProperty("GustStrength")] - public int GustStrength { get; set; } + [JsonProperty("GustStrength")] + public int GustStrength { get; set; } - [JsonProperty("GustAngle")] - public int GustAngle { get; set; } + [JsonProperty("GustAngle")] + public int GustAngle { get; set; } - [JsonProperty("WindStrength")] - public int WindStrength { get; set; } + [JsonProperty("WindStrength")] + public int WindStrength { get; set; } - [JsonProperty("WindAngle")] - public int WindAngle { get; set; } - } + [JsonProperty("WindAngle")] + public int WindAngle { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/WindHistoric.cs b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/WindHistoric.cs index 5bbc6a6..d11d4c3 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/WindHistoric.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/DashboardData/WindHistoric.cs @@ -1,17 +1,16 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client.Weather.StationsData.DashboardData +namespace Netatmo.Models.Client.Weather.StationsData.DashboardData; + +public class WindHistoric : IWindHistory { - public class WindHistoric : IWindHistory - { - [JsonProperty("WindStrength")] - public int WindStrength { get; set; } + [JsonProperty("WindStrength")] + public int WindStrength { get; set; } - [JsonProperty("WindAngle")] - public int WindAngle { get; set; } + [JsonProperty("WindAngle")] + public int WindAngle { get; set; } - [JsonProperty("time_utc")] - public Instant TimeUtc { get; set; } - } + [JsonProperty("time_utc")] + public Instant TimeUtc { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/Device.cs b/src/Netatmo/Models/Client/Weather/StationsData/Device.cs index bc4b4df..e251e4a 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/Device.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/Device.cs @@ -3,67 +3,66 @@ using Newtonsoft.Json; using NodaTime; -namespace Netatmo.Models.Client.Weather.StationsData +namespace Netatmo.Models.Client.Weather.StationsData; + +public class Device { - public class Device - { - [JsonProperty("_id")] - public string Id { get; set; } + [JsonProperty("_id")] + public string Id { get; set; } - [JsonProperty("cipher_id")] - public string CipherId { get; set; } + [JsonProperty("cipher_id")] + public string CipherId { get; set; } - [JsonProperty("station_name")] - public string StationName { get; set; } + [JsonProperty("station_name")] + public string StationName { get; set; } - // NAMain: Base station, NAModule1: Outdoor Module, NAModule2: Wind Gauge, NAModule3: Rain Gauge, NAModule4: Optional indoor module - [JsonProperty("type")] - public string Type { get; set; } + // NAMain: Base station, NAModule1: Outdoor Module, NAModule2: Wind Gauge, NAModule3: Rain Gauge, NAModule4: Optional indoor module + [JsonProperty("type")] + public string Type { get; set; } - // Wifi signal quality : 56 Good, 71 Average, 86 Bad - [JsonProperty("wifi_status")] - public int WifiStatus { get; set; } + // Wifi signal quality : 56 Good, 71 Average, 86 Bad + [JsonProperty("wifi_status")] + public int WifiStatus { get; set; } - public WifiStrengthEnum WifiStrength + public WifiStrengthEnum WifiStrength + { + get { - get - { - if (WifiStatus <= 56) return WifiStrengthEnum.Good; + if (WifiStatus <= 56) return WifiStrengthEnum.Good; - if (WifiStatus <= 71) return WifiStrengthEnum.Average; + if (WifiStatus <= 71) return WifiStrengthEnum.Average; - return WifiStrengthEnum.Bad; - } + return WifiStrengthEnum.Bad; } + } - [JsonProperty("module_name")] - public string ModuleName { get; set; } + [JsonProperty("module_name")] + public string ModuleName { get; set; } - [JsonProperty("co2_calibrating")] - public bool Co2Calibrating { get; set; } + [JsonProperty("co2_calibrating")] + public bool Co2Calibrating { get; set; } - [JsonProperty("firmware")] - public int Firmware { get; set; } + [JsonProperty("firmware")] + public int Firmware { get; set; } - [JsonProperty("date_setup")] - public Instant SetupAt { get; set; } + [JsonProperty("date_setup")] + public Instant SetupAt { get; set; } - [JsonProperty("last_setup")] - public Instant LastSetupAt { get; set; } + [JsonProperty("last_setup")] + public Instant LastSetupAt { get; set; } - [JsonProperty("last_status_store")] - public Instant LastStatusStoreAt { get; set; } + [JsonProperty("last_status_store")] + public Instant LastStatusStoreAt { get; set; } - [JsonProperty("dashboard_data")] - public BaseStationDashBoardData DashboardData { get; set; } + [JsonProperty("dashboard_data")] + public BaseStationDashBoardData DashboardData { get; set; } - [JsonProperty("data_type")] - public string[] DataType { get; set; } + [JsonProperty("data_type")] + public string[] DataType { get; set; } - [JsonProperty("place")] - public Place Place { get; set; } + [JsonProperty("place")] + public Place Place { get; set; } - [JsonProperty("modules")] - public Module[] Modules { get; set; } - } + [JsonProperty("modules")] + public Module[] Modules { get; set; } } \ No newline at end of file diff --git a/src/Netatmo/Models/Client/Weather/StationsData/Module.cs b/src/Netatmo/Models/Client/Weather/StationsData/Module.cs index defaba7..e34dccc 100644 --- a/src/Netatmo/Models/Client/Weather/StationsData/Module.cs +++ b/src/Netatmo/Models/Client/Weather/StationsData/Module.cs @@ -1,152 +1,150 @@ -using System; using Netatmo.Enums; using Netatmo.Models.Client.Weather.StationsData.DashboardData; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NodaTime; -namespace Netatmo.Models.Client.Weather.StationsData +namespace Netatmo.Models.Client.Weather.StationsData; + +public class Module { - public class Module - { - [JsonProperty("_id")] - public string Id { get; set; } + [JsonProperty("_id")] + public string Id { get; set; } - // NAMain: Base station, NAModule1: Outdoor Module, NAModule2: Wind Gauge, NAModule3: Rain Gauge, NAModule4: Optional indoor module - [JsonProperty("type")] - public string Type { get; set; } + // NAMain: Base station, NAModule1: Outdoor Module, NAModule2: Wind Gauge, NAModule3: Rain Gauge, NAModule4: Optional indoor module + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("module_name")] - public string ModuleName { get; set; } + [JsonProperty("module_name")] + public string ModuleName { get; set; } - // Current radio status per module. (90=low, 60=highest) - [JsonProperty("rf_status")] - public int RfStatus { get; set; } + // Current radio status per module. (90=low, 60=highest) + [JsonProperty("rf_status")] + public int RfStatus { get; set; } - public RfStrengthEnum RfStrength + public RfStrengthEnum RfStrength + { + get { - get - { - if (RfStatus <= 60) return RfStrengthEnum.FullSignal; + if (RfStatus <= 60) return RfStrengthEnum.FullSignal; - if (RfStatus <= 70) return RfStrengthEnum.High; + if (RfStatus <= 70) return RfStrengthEnum.High; - if (RfStatus <= 80) return RfStrengthEnum.Medium; + if (RfStatus <= 80) return RfStrengthEnum.Medium; - return RfStrengthEnum.Low; - } + return RfStrengthEnum.Low; } + } - // Percentage of battery remaining (10=low) - [JsonProperty("battery_percent")] - public int BatteryPercent { get; set; } + // Percentage of battery remaining (10=low) + [JsonProperty("battery_percent")] + public int BatteryPercent { get; set; } - [JsonProperty("battery_vp")] - public int BatteryVp { get; set; } + [JsonProperty("battery_vp")] + public int BatteryVp { get; set; } - public BatteryLevelEnum BatteryStatus + public BatteryLevelEnum BatteryStatus + { + get { - get + switch (Type) { - switch (Type) - { - case "NAModule2" when BatteryVp >= 6000: - return BatteryLevelEnum.Max; - case "NAModule2" when BatteryVp >= 5590: - return BatteryLevelEnum.Full; - case "NAModule2" when BatteryVp >= 5180: - return BatteryLevelEnum.High; - case "NAModule2" when BatteryVp >= 4770: - return BatteryLevelEnum.Medium; - case "NAModule2" when BatteryVp >= 4360: - return BatteryLevelEnum.Low; - case "NAModule2": - return BatteryLevelEnum.VeryLow; - case "NAModule4" when BatteryVp >= 6000: - return BatteryLevelEnum.Max; - case "NAModule4" when BatteryVp >= 5640: - return BatteryLevelEnum.Full; - case "NAModule4" when BatteryVp >= 5280: - return BatteryLevelEnum.High; - case "NAModule4" when BatteryVp >= 4920: - return BatteryLevelEnum.Medium; - case "NAModule4" when BatteryVp >= 4560: - return BatteryLevelEnum.Low; - case "NAModule4": - return BatteryLevelEnum.VeryLow; - case "NAModule1" when BatteryVp >= 6000: - case "NAModule3" when BatteryVp >= 6000: - return BatteryLevelEnum.Max; - case "NAModule1" when BatteryVp >= 5500: - case "NAModule3" when BatteryVp >= 5500: - return BatteryLevelEnum.Full; - case "NAModule1" when BatteryVp >= 5000: - case "NAModule3" when BatteryVp >= 5000: - return BatteryLevelEnum.High; - case "NAModule1" when BatteryVp >= 4500: - case "NAModule3" when BatteryVp >= 4500: - return BatteryLevelEnum.Medium; - case "NAModule1" when BatteryVp >= 4000: - case "NAModule3" when BatteryVp >= 4000: - return BatteryLevelEnum.Low; - case "NAModule1": - case "NAModule3": - return BatteryLevelEnum.VeryLow; - default: - return BatteryLevelEnum.Undefined; - } + case "NAModule2" when BatteryVp >= 6000: + return BatteryLevelEnum.Max; + case "NAModule2" when BatteryVp >= 5590: + return BatteryLevelEnum.Full; + case "NAModule2" when BatteryVp >= 5180: + return BatteryLevelEnum.High; + case "NAModule2" when BatteryVp >= 4770: + return BatteryLevelEnum.Medium; + case "NAModule2" when BatteryVp >= 4360: + return BatteryLevelEnum.Low; + case "NAModule2": + return BatteryLevelEnum.VeryLow; + case "NAModule4" when BatteryVp >= 6000: + return BatteryLevelEnum.Max; + case "NAModule4" when BatteryVp >= 5640: + return BatteryLevelEnum.Full; + case "NAModule4" when BatteryVp >= 5280: + return BatteryLevelEnum.High; + case "NAModule4" when BatteryVp >= 4920: + return BatteryLevelEnum.Medium; + case "NAModule4" when BatteryVp >= 4560: + return BatteryLevelEnum.Low; + case "NAModule4": + return BatteryLevelEnum.VeryLow; + case "NAModule1" when BatteryVp >= 6000: + case "NAModule3" when BatteryVp >= 6000: + return BatteryLevelEnum.Max; + case "NAModule1" when BatteryVp >= 5500: + case "NAModule3" when BatteryVp >= 5500: + return BatteryLevelEnum.Full; + case "NAModule1" when BatteryVp >= 5000: + case "NAModule3" when BatteryVp >= 5000: + return BatteryLevelEnum.High; + case "NAModule1" when BatteryVp >= 4500: + case "NAModule3" when BatteryVp >= 4500: + return BatteryLevelEnum.Medium; + case "NAModule1" when BatteryVp >= 4000: + case "NAModule3" when BatteryVp >= 4000: + return BatteryLevelEnum.Low; + case "NAModule1": + case "NAModule3": + return BatteryLevelEnum.VeryLow; + default: + return BatteryLevelEnum.Undefined; } } + } - [JsonProperty("firmware")] - public int Firmware { get; set; } + [JsonProperty("firmware")] + public int Firmware { get; set; } - [JsonProperty("last_message")] - public Instant LastMessageAt { get; set; } + [JsonProperty("last_message")] + public Instant LastMessageAt { get; set; } - [JsonProperty("last_seen")] - public Instant LastSeenAt { get; set; } + [JsonProperty("last_seen")] + public Instant LastSeenAt { get; set; } - [JsonProperty("last_setup")] - public Instant LastSetupAt { get; set; } + [JsonProperty("last_setup")] + public Instant LastSetupAt { get; set; } - [JsonProperty("data_type")] - public string[] DataType { get; set; } + [JsonProperty("data_type")] + public string[] DataType { get; set; } - [JsonProperty("dashboard_data")] - public JObject DashboardData { get; set; } + [JsonProperty("dashboard_data")] + public JObject DashboardData { get; set; } - public T GetDashboardData()where T : IDashBoardData + public T GetDashboardData()where T : IDashBoardData + { + Type expectedType; + switch(Type) { - Type expectedType; - switch(Type) - { - case "NAMain": - expectedType = typeof(BaseStationDashBoardData); - break; - case "NAModule1": - expectedType = typeof(OutdoorDashBoardData); - break; - case "NAModule2": - expectedType = typeof(WindGaugeDashBoardData); - break; - case "NAModule3": - expectedType = typeof(RainGaugeDashBoardData); - break; - case "NAModule4": - expectedType = typeof(IndoorDashBoardData); - break; - default: - expectedType = typeof(DashBoardData); - break; - } + case "NAMain": + expectedType = typeof(BaseStationDashBoardData); + break; + case "NAModule1": + expectedType = typeof(OutdoorDashBoardData); + break; + case "NAModule2": + expectedType = typeof(WindGaugeDashBoardData); + break; + case "NAModule3": + expectedType = typeof(RainGaugeDashBoardData); + break; + case "NAModule4": + expectedType = typeof(IndoorDashBoardData); + break; + default: + expectedType = typeof(DashBoardData); + break; + } - if (expectedType != typeof(T)) - { - throw new ArgumentException($"{expectedType.Name} should be expected"); - } - - return JsonConvert.DeserializeObject(DashboardData.ToString(), Configuration.JsonSerializer()); + if (expectedType != typeof(T)) + { + throw new ArgumentException($"{expectedType.Name} should be expected"); } + + return JsonConvert.DeserializeObject(DashboardData.ToString(), Configuration.JsonSerializer()); } } \ No newline at end of file diff --git a/src/Netatmo/Models/CredentialToken.cs b/src/Netatmo/Models/CredentialToken.cs index 6817981..d1338d5 100644 --- a/src/Netatmo/Models/CredentialToken.cs +++ b/src/Netatmo/Models/CredentialToken.cs @@ -1,26 +1,14 @@ using Netatmo.Models.Client; using NodaTime; -namespace Netatmo.Models +namespace Netatmo.Models; + +public record CredentialToken(int ExpiresIn, string AccessToken, string RefreshToken, Instant ReceivedAt) { - public class CredentialToken + public CredentialToken(Token token, IClock clock) + : this(token.ExpiresIn, token.AccessToken, token.RefreshToken, clock.GetCurrentInstant()) { - public CredentialToken(Token token, IClock clock) - { - ReceivedAt = clock.GetCurrentInstant(); - ExpiresIn = token.ExpiresIn; - AccessToken = token.AccessToken; - RefreshToken = token.RefreshToken; - } - - public int ExpiresIn { get; } - - public string AccessToken { get; } - - public string RefreshToken { get; } - - public Instant ReceivedAt { get; } - - public Instant ExpiresAt => ReceivedAt.Plus(Duration.FromSeconds(ExpiresIn)); } + + public Instant ExpiresAt => ReceivedAt.Plus(Duration.FromSeconds(ExpiresIn)); } \ No newline at end of file diff --git a/src/Netatmo/Netatmo.csproj b/src/Netatmo/Netatmo.csproj index a033a00..ea1dc0b 100644 --- a/src/Netatmo/Netatmo.csproj +++ b/src/Netatmo/Netatmo.csproj @@ -1,7 +1,9 @@ 2.0.0 - net5.0;netstandard2.1;netstandard2.0;netcoreapp3.1 + net6.0 + latest + enable true @@ -24,8 +26,8 @@ - - + + diff --git a/src/Netatmo/Scale.cs b/src/Netatmo/Scale.cs index 02a372b..fbfa960 100644 --- a/src/Netatmo/Scale.cs +++ b/src/Netatmo/Scale.cs @@ -1,56 +1,53 @@ -using System; +namespace Netatmo; -namespace Netatmo +public class Scale : IEquatable { - public class Scale : IEquatable + private Scale(string value) { - private Scale(string value) - { - Value = value; - } - - public string Value { get; } - public static Scale Max => new Scale("max"); - public static Scale HalfHour => new Scale("30min"); - public static Scale OneHour => new Scale("1hour"); - public static Scale ThreeHours => new Scale("3hours"); - public static Scale OneDay => new Scale("1day"); - public static Scale OneWeek => new Scale("1week"); - public static Scale OneMonth => new Scale("1month"); - - public bool Equals(Scale other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return string.Equals(Value, other.Value); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != GetType()) return false; - return Equals((Scale) obj); - } - - public override int GetHashCode() - { - return Value != null ? Value.GetHashCode() : 0; - } - - public static bool operator ==(Scale obj1, Scale obj2) - { - if (ReferenceEquals(obj1, obj2)) return true; - - if (ReferenceEquals(obj1, null)) return false; - if (ReferenceEquals(obj2, null)) return false; - - return obj1.Equals(obj2); - } - - public static bool operator !=(Scale obj1, Scale obj2) - { - return !(obj1 == obj2); - } + Value = value; + } + + public string Value { get; } + public static Scale Max => new Scale("max"); + public static Scale HalfHour => new Scale("30min"); + public static Scale OneHour => new Scale("1hour"); + public static Scale ThreeHours => new Scale("3hours"); + public static Scale OneDay => new Scale("1day"); + public static Scale OneWeek => new Scale("1week"); + public static Scale OneMonth => new Scale("1month"); + + public bool Equals(Scale other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return string.Equals(Value, other.Value); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((Scale) obj); + } + + public override int GetHashCode() + { + return Value != null ? Value.GetHashCode() : 0; + } + + public static bool operator ==(Scale obj1, Scale obj2) + { + if (ReferenceEquals(obj1, obj2)) return true; + + if (ReferenceEquals(obj1, null)) return false; + if (ReferenceEquals(obj2, null)) return false; + + return obj1.Equals(obj2); + } + + public static bool operator !=(Scale obj1, Scale obj2) + { + return !(obj1 == obj2); } } \ No newline at end of file diff --git a/src/Netatmo/Scope.cs b/src/Netatmo/Scope.cs index 378657e..819a21e 100644 --- a/src/Netatmo/Scope.cs +++ b/src/Netatmo/Scope.cs @@ -1,58 +1,55 @@ -using System; +namespace Netatmo; -namespace Netatmo +public class Scope : IEquatable { - public class Scope : IEquatable + private Scope(string value) { - private Scope(string value) - { - Value = value; - } - - public string Value { get; } - public static Scope StationRead => new Scope("read_station"); - public static Scope ThermostatRead => new Scope("read_thermostat"); - public static Scope StationWrite => new Scope("write_thermostat"); - public static Scope CameraRead => new Scope("read_camera"); - public static Scope CameraWrite => new Scope("write_camera"); - public static Scope CameraAccess => new Scope("access_camera"); - public static Scope PresenceRead => new Scope("read_presence"); - public static Scope PresenceAccess => new Scope("access_presence"); - public static Scope HomecoachRead => new Scope("read_homecoach"); - - public bool Equals(Scope other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return string.Equals(Value, other.Value); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != GetType()) return false; - return Equals((Scope) obj); - } - - public override int GetHashCode() - { - return Value != null ? Value.GetHashCode() : 0; - } - - public static bool operator ==(Scope obj1, Scope obj2) - { - if (ReferenceEquals(obj1, obj2)) return true; - - if (ReferenceEquals(obj1, null)) return false; - if (ReferenceEquals(obj2, null)) return false; - - return obj1.Equals(obj2); - } - - public static bool operator !=(Scope obj1, Scope obj2) - { - return !(obj1 == obj2); - } + Value = value; + } + + public string Value { get; } + public static Scope StationRead => new Scope("read_station"); + public static Scope ThermostatRead => new Scope("read_thermostat"); + public static Scope StationWrite => new Scope("write_thermostat"); + public static Scope CameraRead => new Scope("read_camera"); + public static Scope CameraWrite => new Scope("write_camera"); + public static Scope CameraAccess => new Scope("access_camera"); + public static Scope PresenceRead => new Scope("read_presence"); + public static Scope PresenceAccess => new Scope("access_presence"); + public static Scope HomecoachRead => new Scope("read_homecoach"); + + public bool Equals(Scope other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return string.Equals(Value, other.Value); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((Scope) obj); + } + + public override int GetHashCode() + { + return Value != null ? Value.GetHashCode() : 0; + } + + public static bool operator ==(Scope obj1, Scope obj2) + { + if (ReferenceEquals(obj1, obj2)) return true; + + if (ReferenceEquals(obj1, null)) return false; + if (ReferenceEquals(obj2, null)) return false; + + return obj1.Equals(obj2); + } + + public static bool operator !=(Scope obj1, Scope obj2) + { + return !(obj1 == obj2); } } \ No newline at end of file diff --git a/src/Netatmo/ThermostatMeasurementType.cs b/src/Netatmo/ThermostatMeasurementType.cs index d38b662..1f7c65d 100644 --- a/src/Netatmo/ThermostatMeasurementType.cs +++ b/src/Netatmo/ThermostatMeasurementType.cs @@ -1,72 +1,67 @@ -using System; -using System.Collections.Generic; -using System.Linq; +namespace Netatmo; -namespace Netatmo +public class ThermostatMeasurementType : IEquatable { - public class ThermostatMeasurementType : IEquatable + private ThermostatMeasurementType(string value) { - private ThermostatMeasurementType(string value) - { - Value = value; - } + Value = value; + } - public string Value { get; } + public string Value { get; } - public static ThermostatMeasurementType Temperature => new ThermostatMeasurementType("temperature"); - public static ThermostatMeasurementType SetPointTemperature => new ThermostatMeasurementType("sp_temperature"); - public static ThermostatMeasurementType BoilerOn => new ThermostatMeasurementType("boileron"); - public static ThermostatMeasurementType BoilerOff => new ThermostatMeasurementType("boileroff"); - public static ThermostatMeasurementType MinTemp => new ThermostatMeasurementType("min_temp"); - public static ThermostatMeasurementType MaxTemp => new ThermostatMeasurementType("max_temp"); - public static ThermostatMeasurementType SumBoilerOn => new ThermostatMeasurementType("sum_boiler_on"); - public static ThermostatMeasurementType SumBoilerOff => new ThermostatMeasurementType("sum_boiler_off"); - public static ThermostatMeasurementType DateMinTemp => new ThermostatMeasurementType("date_min_temp"); + public static ThermostatMeasurementType Temperature => new ThermostatMeasurementType("temperature"); + public static ThermostatMeasurementType SetPointTemperature => new ThermostatMeasurementType("sp_temperature"); + public static ThermostatMeasurementType BoilerOn => new ThermostatMeasurementType("boileron"); + public static ThermostatMeasurementType BoilerOff => new ThermostatMeasurementType("boileroff"); + public static ThermostatMeasurementType MinTemp => new ThermostatMeasurementType("min_temp"); + public static ThermostatMeasurementType MaxTemp => new ThermostatMeasurementType("max_temp"); + public static ThermostatMeasurementType SumBoilerOn => new ThermostatMeasurementType("sum_boiler_on"); + public static ThermostatMeasurementType SumBoilerOff => new ThermostatMeasurementType("sum_boiler_off"); + public static ThermostatMeasurementType DateMinTemp => new ThermostatMeasurementType("date_min_temp"); - public bool Equals(ThermostatMeasurementType other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return string.Equals(Value, other.Value); - } + public bool Equals(ThermostatMeasurementType other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return string.Equals(Value, other.Value); + } - public static List AvailableTypes(Scale scale) - { - if (new[] {Scale.HalfHour, Scale.OneHour, Scale.ThreeHours}.Any(s => s.Value == scale.Value)) - return new List {Temperature, SetPointTemperature, MinTemp, MaxTemp, SumBoilerOn, SumBoilerOff}; + public static List AvailableTypes(Scale scale) + { + if (new[] {Scale.HalfHour, Scale.OneHour, Scale.ThreeHours}.Any(s => s.Value == scale.Value)) + return new List {Temperature, SetPointTemperature, MinTemp, MaxTemp, SumBoilerOn, SumBoilerOff}; - if (new[] {Scale.OneDay, Scale.OneWeek, Scale.OneMonth}.Any(s => s.Value == scale.Value)) - return new List {Temperature, DateMinTemp, MinTemp, MaxTemp, SumBoilerOn, SumBoilerOff}; + if (new[] {Scale.OneDay, Scale.OneWeek, Scale.OneMonth}.Any(s => s.Value == scale.Value)) + return new List {Temperature, DateMinTemp, MinTemp, MaxTemp, SumBoilerOn, SumBoilerOff}; - return new List {Temperature, SetPointTemperature, BoilerOn, BoilerOff}; - } + return new List {Temperature, SetPointTemperature, BoilerOn, BoilerOff}; + } - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != GetType()) return false; - return Equals((ThermostatMeasurementType) obj); - } + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((ThermostatMeasurementType) obj); + } - public override int GetHashCode() - { - return Value != null ? Value.GetHashCode() : 0; - } + public override int GetHashCode() + { + return Value != null ? Value.GetHashCode() : 0; + } - public static bool operator ==(ThermostatMeasurementType obj1, ThermostatMeasurementType obj2) - { - if (ReferenceEquals(obj1, obj2)) return true; + public static bool operator ==(ThermostatMeasurementType obj1, ThermostatMeasurementType obj2) + { + if (ReferenceEquals(obj1, obj2)) return true; - if (ReferenceEquals(obj1, null)) return false; - if (ReferenceEquals(obj2, null)) return false; + if (ReferenceEquals(obj1, null)) return false; + if (ReferenceEquals(obj2, null)) return false; - return obj1.Equals(obj2); - } + return obj1.Equals(obj2); + } - public static bool operator !=(ThermostatMeasurementType obj1, ThermostatMeasurementType obj2) - { - return !(obj1 == obj2); - } + public static bool operator !=(ThermostatMeasurementType obj1, ThermostatMeasurementType obj2) + { + return !(obj1 == obj2); } } \ No newline at end of file diff --git a/src/Netatmo/WeatherClient.cs b/src/Netatmo/WeatherClient.cs index 285052e..d911914 100644 --- a/src/Netatmo/WeatherClient.cs +++ b/src/Netatmo/WeatherClient.cs @@ -1,33 +1,31 @@ -using System.Threading.Tasks; using Flurl.Http; using Netatmo.Models.Client; using Netatmo.Models.Client.Weather; -namespace Netatmo +namespace Netatmo; + +public class WeatherClient : IWeatherClient { - public class WeatherClient : IWeatherClient - { - private readonly string baseUrl; - private readonly ICredentialManager credentialManager; + private readonly string baseUrl; + private readonly ICredentialManager credentialManager; - public WeatherClient(string baseUrl, ICredentialManager credentialManager) - { - this.credentialManager = credentialManager; - this.baseUrl = baseUrl; - } + public WeatherClient(string baseUrl, ICredentialManager credentialManager) + { + this.credentialManager = credentialManager; + this.baseUrl = baseUrl; + } - public Task> GetStationsData(string deviceId = null, bool? onlyFavorites = null) - { - return baseUrl - .ConfigureRequest(Configuration.ConfigureRequest) - .AppendPathSegment("/api/getstationsdata") - .WithOAuthBearerToken(credentialManager.AccessToken) - .PostJsonAsync(new GetStationsDataRequest - { - DeviceId = deviceId, - GetFavorites = onlyFavorites - }) - .ReceiveJson>(); - } + public Task> GetStationsData(string deviceId = null, bool? onlyFavorites = null) + { + return baseUrl + .ConfigureRequest(Configuration.ConfigureRequest) + .AppendPathSegment("/api/getstationsdata") + .WithOAuthBearerToken(credentialManager.AccessToken) + .PostJsonAsync(new GetStationsDataRequest + { + DeviceId = deviceId, + GetFavorites = onlyFavorites + }) + .ReceiveJson>(); } } \ No newline at end of file diff --git a/src/TestApp/Program.cs b/src/TestApp/Program.cs deleted file mode 100644 index fab82e2..0000000 --- a/src/TestApp/Program.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Flurl.Http; -using Flurl.Util; -using Netatmo; -using Netatmo.Models.Client.Energy; -using Netatmo.Models.Client.Energy.RoomMeasure; -using Newtonsoft.Json; -using NodaTime; - -namespace TestApp -{ - internal class Program - { - public static async Task Main(string[] args) - { - JsonConvert.DefaultSettings = Configuration.JsonSerializer; - - IClient client = new Client( - SystemClock.Instance, "https://api.netatmo.com/", - Environment.GetEnvironmentVariable("NETATMO_CLIENT_ID"), - Environment.GetEnvironmentVariable("NETATMO_CLIENT_SECRET")); - - await client.GenerateToken( - Environment.GetEnvironmentVariable("NETATMO_USERNAME"), - Environment.GetEnvironmentVariable("NETATMO_PASSWORD"), - new[] - { - Scope.CameraAccess, Scope.CameraRead, Scope.CameraWrite, Scope.HomecoachRead, Scope.PresenceAccess, Scope.PresenceRead, Scope.StationRead, - Scope.StationWrite, Scope.ThermostatRead - }); - - var token = client.CredentialManager.CredentialToken; - - Console.WriteLine($"Token : {token.AccessToken}"); - - Console.WriteLine("Stations data :"); - var stationsData = await client.Weather.GetStationsData(); - Console.WriteLine(JsonConvert.SerializeObject(stationsData, Formatting.Indented)); - - Console.WriteLine("Energy Homes data :"); - var homesData = await client.Energy.GetHomesData(); - Console.WriteLine(JsonConvert.SerializeObject(homesData, Formatting.Indented)); - - Console.WriteLine("Energy Homes data :"); - foreach (var home in homesData.Body.Homes) - { - Console.WriteLine(home.Name); - var homeStatus = await client.Energy.GetHomeStatus(home.Id); - Console.WriteLine(JsonConvert.SerializeObject(homeStatus, Formatting.Indented)); - - Console.WriteLine("Energy room measure :"); - foreach (var room in home.Rooms) - { - if (room.ModuleIds == null || !room.ModuleIds.Any()) - { - continue; - } - - Console.WriteLine(room.Name); - var parameters = new GetRoomMeasureParameters - { - HomeId = home.Id, - RoomId = room.Id, - Scale = Scale.Max, - Type = ThermostatMeasurementType.Temperature, - BeginAt = SystemClock.Instance.GetCurrentInstant().Plus(Duration.FromDays(-1)), - EndAt = SystemClock.Instance.GetCurrentInstant() - }; - - try - { - var roomMeasure = await client.Energy.GetRoomMeasure(parameters); - Console.WriteLine(JsonConvert.SerializeObject(roomMeasure, Formatting.Indented)); - } - catch (FlurlHttpException exception) - { - var error = await exception.GetResponseStringAsync(); - Console.WriteLine($"exception : {error}"); - } - } - } - - Console.WriteLine("RefreshToken :"); - Thread.Sleep(9000); - await client.RefreshToken(); - var newToken = client.CredentialManager.CredentialToken; - Console.WriteLine($"Old token expires at : {token.ExpiresAt.ToInvariantString()}"); - Console.WriteLine($"New token expires at : {newToken.ExpiresAt.ToInvariantString()}"); - } - } -} \ No newline at end of file diff --git a/tests/Netatmo.Tests/AirClient.cs b/tests/Netatmo.Tests/AirClient.cs new file mode 100644 index 0000000..f9f2d8b --- /dev/null +++ b/tests/Netatmo.Tests/AirClient.cs @@ -0,0 +1,49 @@ +using Flurl.Http.Testing; +using Netatmo.Enums; +using Netatmo.Models.Client.Air; +using NodaTime; + +namespace Netatmo.Tests; + +public class AirClient : IDisposable +{ + private readonly HttpTest httpTest; + + public AirClient() + { + httpTest = new HttpTest(); + httpTest.Configure(Configuration.ConfigureRequest); + } + + public void Dispose() + { + httpTest.Dispose(); + } + + [Fact] + public async Task GetStationsData_Should_Return_DataResponse_With_AirData() + { + var accessToken = "Super-Access-Token"; + var credentialManagerMock = new Mock(); + credentialManagerMock.Setup(x => x.AccessToken).Returns(accessToken); + + httpTest.RespondWith( + "{\"body\": {\"devices\": [{\"_id\": \"70:xx:xx:xx:xx:c2\",\"cipher_id\": \"enc:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa28Zn\",\"date_setup\": 1548316279,\"last_setup\": 1548316279,\"type\": \"NHC\",\"last_status_store\": 1548331813,\"module_name\": \"Indoor\",\"firmware\": 45,\"last_upgrade\": 1548316280,\"wifi_status\": 49,\"reachable\": true,\"co2_calibrating\": true,\"station_name\": \"Healthy ConX\",\"data_type\": [\"Temperature\",\"CO2\",\"Humidity\",\"Noise\",\"Pressure\",\"health_idx\"],\"place\": {\"altitude\": 491.70001220703,\"country\": \"CH\",\"timezone\": \"Europe/Zurich\",\"location\": [8.3085069,47.0450306]},\"dashboard_data\": {\"time_utc\": 1548331811,\"Temperature\": 22.1,\"CO2\": 647,\"Humidity\": 33,\"Noise\": 44,\"Pressure\": 1018.3,\"AbsolutePressure\": 960.4,\"health_idx\": 0,\"min_temp\": 17.3,\"max_temp\": 23.6,\"date_min_temp\": 1548316040,\"date_max_temp\": 1548316058}}],\"user\": {\"mail\": \"a@mail.ch\",\"administrative\": {\"lang\": \"en-US\",\"reg_locale\": \"en-US\",\"country\": \"CH\",\"unit\": 0,\"windunit\": 0,\"pressureunit\": 0,\"feel_like_algo\": 0}}},\"status\": \"ok\",\"time_exec\": 0.038990020751953,\"time_server\": 1548331875}"); + + var sut = new Netatmo.AirClient("https://api.netatmo.com/", credentialManagerMock.Object); + var result = await sut.GetHomeCoachsData(); + + httpTest.ShouldHaveCalled("https://api.netatmo.com/api/gethomecoachsdata") + .WithVerb(HttpMethod.Post) + .WithOAuthBearerToken(accessToken) + .WithContentType("application/json") + .WithRequestJson(new GetHomeCoachsDataRequest()) + .Times(1); + + result.Body.Should().BeOfType(); + result.Body.Devices[0].DashboardData.Noise.Should().Be(44); + result.Body.Devices[0].WifiStrength.Should().Be(WifiStrengthEnum.Good); + result.Body.Devices[0].DashboardData.HumidityPercent.Should().Be(33); + result.Body.Devices[0].Place.Timezone.Should().Be(DateTimeZoneProviders.Tzdb["Europe/Zurich"]); + } +} \ No newline at end of file diff --git a/tests/Netatmo.Tests/ClassData/Energy/GetRoomMeasureArgumentExceptionData.cs b/tests/Netatmo.Tests/ClassData/Energy/GetRoomMeasureArgumentExceptionData.cs new file mode 100644 index 0000000..04de4d9 --- /dev/null +++ b/tests/Netatmo.Tests/ClassData/Energy/GetRoomMeasureArgumentExceptionData.cs @@ -0,0 +1,60 @@ +using System.Collections; +using Netatmo.Models.Client.Energy; +using NodaTime; + +namespace Netatmo.Tests.ClassData.Energy; + +public class GetRoomMeasureArgumentExceptionData : IEnumerable +{ + public IEnumerator GetEnumerator() + { + yield return new object[] { new GetRoomMeasureParameters(), "Home Id shouldn't be null" }; + yield return new object[] { new GetRoomMeasureParameters { HomeId = "5a327cbdb05a2133678b5d3e" }, "Room Id shouldn't be null" }; + yield return new object[] { new GetRoomMeasureParameters { HomeId = "5a327cbdb05a2133678b5d3e", RoomId = "2255031728" }, "Scale shouldn't be null" }; + yield return new object[] { new GetRoomMeasureParameters { HomeId = "5a327cbdb05a2133678b5d3e", RoomId = "2255031728", Scale = Scale.Max }, "Type shouldn't be null" }; + yield return new object[] + { + new GetRoomMeasureParameters { HomeId = "5a327cbdb05a2133678b5d3e", RoomId = "2255031728", Scale = Scale.Max, Type = ThermostatMeasurementType.DateMinTemp }, + "Type shouldn't be allow for this scale" + }; + yield return new object[] + { + new GetRoomMeasureParameters + { + HomeId = "5a327cbdb05a2133678b5d3e", + RoomId = "2255031728", + Scale = Scale.Max, + Type = ThermostatMeasurementType.Temperature, + Limit = 2000 + }, + "Limit should be between 0 and 1024" + }; + yield return new object[] + { + new GetRoomMeasureParameters + { + HomeId = "5a327cbdb05a2133678b5d3e", + RoomId = "2255031728", + Scale = Scale.Max, + Type = ThermostatMeasurementType.Temperature, + Limit = -42 + }, + "Limit should be between 0 and 1024" + }; + yield return new object[] + { + new GetRoomMeasureParameters + { + HomeId = "5a327cbdb05a2133678b5d3e", + RoomId = "2255031728", + Scale = Scale.Max, + Type = ThermostatMeasurementType.Temperature, + BeginAt = Instant.FromDateTimeUtc(DateTime.SpecifyKind(new DateTime(2018, 4, 30), DateTimeKind.Utc)), + EndAt = Instant.FromDateTimeUtc(DateTime.SpecifyKind(new DateTime(2017, 4, 30), DateTimeKind.Utc)) + }, + "BeginAt should be lower than EndAt" + }; + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} \ No newline at end of file diff --git a/tests/Netatmo.Tests/CredentialManager.cs b/tests/Netatmo.Tests/CredentialManager.cs new file mode 100644 index 0000000..9642419 --- /dev/null +++ b/tests/Netatmo.Tests/CredentialManager.cs @@ -0,0 +1,112 @@ +using Flurl.Http.Testing; +using Netatmo.Models; +using NodaTime; +using NodaTime.Testing; + +namespace Netatmo.Tests; + +public class CredentialManager : IDisposable +{ + private readonly HttpTest httpTest; + + public CredentialManager() + { + httpTest = new HttpTest(); + } + + public void Dispose() + { + httpTest.Dispose(); + } + + [Fact] + public async Task GenerateToken_Should_Acquire_Excepted_CredentialToken() + { + var expectedToken = new { access_token = "2YotnFZFEjr1zCsicMWpAA", expires_in = 10800, refresh_token = "tGzv3JOkF0XG5Qx2TlKWIA" }; + + httpTest.RespondWithJson(expectedToken); + + var sut = new Netatmo.CredentialManager("https://api.netatmo.com/", "clientId", "clientSecret", SystemClock.Instance); + + await sut.GenerateToken( + "username@email.com", + "p@$$W0rd", + new[] + { + Scope.CameraAccess, + Scope.CameraRead, + Scope.CameraWrite, + Scope.HomecoachRead, + Scope.PresenceAccess, + Scope.PresenceRead, + Scope.StationRead, + Scope.StationWrite, + Scope.ThermostatRead + }); + + var token = sut.CredentialToken; + + httpTest.ShouldHaveCalled("https://api.netatmo.com/oauth2/token") + .WithVerb(HttpMethod.Post) + .WithContentType("application/x-www-form-urlencoded") + .WithRequestBody( + "grant_type=password&client_id=clientId&client_secret=clientSecret&username=username%40email.com&password=p%40%24%24W0rd&scope=access_camera+read_camera+write_camera+read_homecoach+access_presence+read_presence+read_station+write_thermostat+read_thermostat") + .Times(1); + + token.Should().BeOfType(); + token.AccessToken.Should().Be(expectedToken.access_token); + token.RefreshToken.Should().Be(expectedToken.refresh_token); + token.ExpiresAt.Should().Be(token.ReceivedAt.Plus(Duration.FromSeconds(expectedToken.expires_in))); + } + + [Fact] + public void ProvideOAuth2Token_Should_Provide_Token_From_Existing() + { + var expectedToken = new { access_token = "2YotnFZFEjr1zCsicMWpAA", expires_in = 20 }; + + httpTest.RespondWithJson(expectedToken); + + var sut = new Netatmo.CredentialManager("https://api.netatmo.com/", "clientId", "clientSecret", SystemClock.Instance); + + sut.ProvideOAuth2Token(expectedToken.access_token); + + var token = sut.CredentialToken; + + token.Should().BeOfType(); + token.AccessToken.Should().Be(expectedToken.access_token); + token.RefreshToken.Should().BeNull(); + token.ExpiresAt.Should().Be(token.ReceivedAt.Plus(Duration.FromSeconds(expectedToken.expires_in))); + } + + [Fact] + public async Task RefreshToken_Should_Refresh_Token() + { + var token = new { access_token = "2YotnFZFEjr1zCsicMWpAA", expires_in = 10800, refresh_token = "tGzv3JOkF0XG5Qx2TlKWIA" }; + + var expectedToken = new { access_token = "dGVzdGNsaWVudDpzZWNyZXQ", expires_in = 10800, refresh_token = "fdb8fdbecf1d03ce5e6125c067733c0d51de209c" }; + + httpTest.RespondWithJson(token); + httpTest.RespondWithJson(expectedToken); + + var fakeClock = new FakeClock(SystemClock.Instance.GetCurrentInstant(), Duration.FromMinutes(-2)); + + var sut = new Netatmo.CredentialManager("https://api.netatmo.com/", "clientId", "clientSecret", fakeClock); + + await sut.GenerateToken("username@email.com", "p@$$W0rd"); + var oldToken = sut.CredentialToken; + await sut.RefreshToken(); + var refreshedToken = sut.CredentialToken; + + httpTest.ShouldHaveCalled("https://api.netatmo.com/oauth2/token") + .WithVerb(HttpMethod.Post) + .WithContentType("application/x-www-form-urlencoded") + .WithRequestBody($"grant_type=refresh_token&client_id=clientId&client_secret=clientSecret&refresh_token={oldToken.RefreshToken}") + .Times(1); + + refreshedToken.Should().BeOfType(); + refreshedToken.AccessToken.Should().Be(expectedToken.access_token); + refreshedToken.RefreshToken.Should().Be(expectedToken.refresh_token); + refreshedToken.ExpiresAt.Should().Be(refreshedToken.ReceivedAt.Plus(Duration.FromSeconds(expectedToken.expires_in))); + refreshedToken.Should().NotBe(oldToken); + } +} \ No newline at end of file diff --git a/tests/Netatmo.Tests/EnergyClient.cs b/tests/Netatmo.Tests/EnergyClient.cs new file mode 100644 index 0000000..438c8ac --- /dev/null +++ b/tests/Netatmo.Tests/EnergyClient.cs @@ -0,0 +1,264 @@ +using Flurl.Http.Testing; +using Netatmo.Enums; +using Netatmo.Models.Client; +using Netatmo.Models.Client.Energy; +using Netatmo.Models.Client.Energy.RoomMeasure; +using Netatmo.Tests.ClassData.Energy; +using NodaTime; + +namespace Netatmo.Tests; + +public class EnergyClient : IDisposable +{ + private readonly string accessToken; + private readonly Mock credentialManagerMock; + + private readonly HttpTest httpTest; + + public EnergyClient() + { + httpTest = new HttpTest(); + httpTest.Configure(Configuration.ConfigureRequest); + + accessToken = "Super-Access-Token"; + credentialManagerMock = new Mock(); + credentialManagerMock.Setup(x => x.AccessToken).Returns(accessToken); + } + + public void Dispose() + { + httpTest.Dispose(); + } + + [Fact] + public async Task CreateHomeSchedule_Should_Return_Expected_Result() + { + var parameters = new CreateHomeScheduleRequest("5a327cbdb05a2133678b5d3e", 14, 16, "Cat schedule"); + httpTest.RespondWithJson(new CreateHomeScheduleResponse("ok", 0.036107063293457, Instant.FromUnixTimeSeconds(1518023467), "5a819e6113475d09c28b497a")); + + var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); + await sut.CreateHomeSchedule(parameters); + + httpTest.ShouldHaveCalled("https://api.netatmo.com/api/createnewhomeschedule") + .WithVerb(HttpMethod.Post) + .WithOAuthBearerToken(accessToken) + .WithContentType("application/json") + .WithRequestJson( + new CreateHomeScheduleRequest(parameters.HomeId, parameters.HgTemp, parameters.AwayTemp, parameters.Name, Array.Empty(), Array.Empty())) + .Times(1); + } + + [Fact] + public async Task DeleteHomeSchedule_Should_Return_Expected_Result() + { + var homeId = "5a327cbdb05a2133678b5d3e"; + var scheduleId = "5a327cbdb05a2133678b5d3f"; + httpTest.RespondWithJson(new DataResponse("ok", 0.036107063293457, Instant.FromUnixTimeSeconds(1518023467))); + + var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); + await sut.DeleteHomeSchedule(homeId, scheduleId); + + httpTest.ShouldHaveCalled("https://api.netatmo.com/api/deletehomeschedule") + .WithVerb(HttpMethod.Post) + .WithOAuthBearerToken(accessToken) + .WithContentType("application/json") + .WithRequestJson(new DeleteHomeScheduleRequest { HomeId = homeId, ScheduleId = scheduleId }) + .Times(1); + } + + [Fact] + public async Task GetHomesData_Should_Return_DataResponse_With_HomesData() + { + httpTest.RespondWith( + "{\"body\":{\"homes\":[{\"id\":\"5a327cbdb05a2133678b5d3e\",\"name\":\"test\",\"altitude\":88,\"coordinates\":[2.2395809,48.829662],\"country\":\"FR\",\"timezone\":\"Europe\\/Paris\",\"rooms\":[{\"id\":\"2255031728\",\"name\":\"Salon\",\"type\":\"livingroom\",\"module_ids\":[\"04:00:00:23:f2:10\"],\"measure_offset_NAPlug_temperature\":0,\"measure_offset_NAPlug_estimated_temperature\":0},{\"id\":\"2539094912\",\"name\":\"Chambre\",\"type\":\"bedroom\",\"module_ids\":[\"09:00:00:00:0b:bd\"],\"measure_offset_NAPlug_temperature\":0,\"measure_offset_NAPlug_estimated_temperature\":0}],\"modules\":[{\"id\":\"70:ee:50:23:d7:a8\",\"type\":\"NAPlug\",\"name\":\"Relais\",\"setup_date\":1513259804,\"modules_bridged\":[\"04:00:00:23:f2:10\",\"09:00:00:00:0b:bd\"]},{\"id\":\"04:00:00:23:f2:10\",\"type\":\"NATherm1\",\"name\":\"Thermostat\",\"setup_date\":1513259817,\"room_id\":\"2255031728\",\"bridge\":\"70:ee:50:23:d7:a8\"},{\"id\":\"09:00:00:00:0b:bd\",\"type\":\"NRV\",\"name\":\"Vanne Salon\",\"setup_date\":1513260804,\"room_id\":\"2539094912\",\"bridge\":\"70:ee:50:23:d7:a8\"}],\"schedules\":[{\"away_temp\":12,\"default\":true,\"hg_temp\":7,\"timetable\":[{\"m_offset\":0,\"zone_id\":1},{\"m_offset\":420,\"zone_id\":3},{\"m_offset\":450,\"zone_id\":0},{\"m_offset\":480,\"zone_id\":4},{\"m_offset\":1140,\"zone_id\":0},{\"m_offset\":1290,\"zone_id\":3},{\"m_offset\":1320,\"zone_id\":1},{\"m_offset\":1860,\"zone_id\":3},{\"m_offset\":1890,\"zone_id\":0},{\"m_offset\":1920,\"zone_id\":4},{\"m_offset\":2580,\"zone_id\":0},{\"m_offset\":2730,\"zone_id\":3},{\"m_offset\":2760,\"zone_id\":1},{\"m_offset\":3300,\"zone_id\":3},{\"m_offset\":3330,\"zone_id\":0},{\"m_offset\":3360,\"zone_id\":4},{\"m_offset\":4020,\"zone_id\":0},{\"m_offset\":4170,\"zone_id\":3},{\"m_offset\":4200,\"zone_id\":1},{\"m_offset\":4740,\"zone_id\":3},{\"m_offset\":4770,\"zone_id\":0},{\"m_offset\":4800,\"zone_id\":4},{\"m_offset\":5460,\"zone_id\":0},{\"m_offset\":5610,\"zone_id\":3},{\"m_offset\":5640,\"zone_id\":1},{\"m_offset\":6180,\"zone_id\":3},{\"m_offset\":6210,\"zone_id\":0},{\"m_offset\":6240,\"zone_id\":4},{\"m_offset\":6900,\"zone_id\":0},{\"m_offset\":7050,\"zone_id\":3},{\"m_offset\":7080,\"zone_id\":1},{\"m_offset\":7620,\"zone_id\":3},{\"m_offset\":7650,\"zone_id\":0},{\"m_offset\":8490,\"zone_id\":3},{\"m_offset\":8520,\"zone_id\":1},{\"m_offset\":9060,\"zone_id\":3},{\"m_offset\":9090,\"zone_id\":0},{\"m_offset\":9930,\"zone_id\":3},{\"m_offset\":9960,\"zone_id\":1}],\"zones\":[{\"type\":0,\"id\":0,\"rooms\":[{\"id\":\"2255031728\",\"therm_setpoint_temperature\":19},{\"room_id\":\"2539094912\",\"therm_setpoint_temperature\":17}]},{\"type\":1,\"id\":1,\"rooms\":[{\"id\":\"2255031728\",\"therm_setpoint_temperature\":16},{\"id\":\"2539094912\",\"therm_setpoint_temperature\":17}]},{\"type\":8,\"id\":3,\"rooms\":[{\"id\":\"2255031728\",\"therm_setpoint_temperature\":19},{\"id\":\"2539094912\",\"therm_setpoint_temperature\":17}]},{\"type\":5,\"id\":4,\"rooms\":[{\"id\":\"2255031728\",\"therm_setpoint_temperature\":16},{\"id\":\"2539094912\",\"therm_setpoint_temperature\":16}]}],\"id\":\"5a327cbdb05a2133678b5d3f\",\"selected\":true,\"type\":\"therm\"}],\"therm_setpoint_default_duration\":180,\"therm_mode\":\"schedule\"}],\"user\":{\"email\":\"example@domain.com\",\"language\":\"fr-FR\",\"locale\":\"en-FR\",\"feel_like_algorithm\":0,\"unit_pressure\":0,\"unit_system\":0,\"unit_wind\":0,\"id\":\"user_id\"}},\"status\":\"ok\",\"time_exec\":0.08151913,\"time_server\":1518022817}"); + + var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); + var result = await sut.GetHomesData(); + + httpTest.ShouldHaveCalled("https://api.netatmo.com/api/homesdata") + .WithVerb(HttpMethod.Post) + .WithOAuthBearerToken(accessToken) + .WithContentType("application/json") + .WithRequestJson(new GetHomesDataRequest()) + .Times(1); + + result.Body.Should().BeOfType(); + result.Body.Homes[0].Modules[0].ModulesBridged.Should().Equal("04:00:00:23:f2:10", "09:00:00:00:0b:bd"); + } + + [Fact] + public async Task GetHomeStatus_Should_Return_DataResponse_With_HomeStatus() + { + var homeId = "5a327cbdb05a2133678b5d3e"; + httpTest.RespondWith( + "{\"status\":\"ok\",\"time_server\":1518023129,\"body\":{\"home\":{\"modules\":[{\"id\":\"70:ee:50:23:d7:a8\",\"type\":\"NAPlug\",\"rf_strength\":104,\"wifi_strength\":38},{\"id\":\"04:00:00:23:f2:10\",\"reachable\":true,\"type\":\"NATherm1\",\"firmware_revision\":65,\"rf_strength\":26,\"battery_level\":4478,\"boiler_valve_comfort_boost\":false,\"boiler_status\":false,\"anticipating\":false,\"bridge\":\"70:ee:50:23:d7:a8\",\"battery_state\":\"full\"},{\"id\":\"09:00:00:00:0b:bd\",\"reachable\":true,\"type\":\"NRV\",\"firmware_revision\":51,\"rf_strength\":44,\"battery_level\":2982,\"bridge\":\"70:ee:50:23:d7:a8\",\"battery_state\":\"high\"}],\"rooms\":[{\"id\":\"2255031728\",\"reachable\":true,\"therm_measured_temperature\":25.3,\"therm_setpoint_temperature\":16,\"therm_setpoint_mode\":\"schedule\",\"therm_setpoint_start_time\":1517986800,\"therm_setpoint_end_time\":0},{\"id\":\"2539094912\",\"reachable\":true,\"therm_measured_temperature\":24,\"heating_power_request\":0,\"therm_setpoint_temperature\":16,\"therm_setpoint_mode\":\"schedule\",\"therm_setpoint_start_time\":1517986800,\"therm_setpoint_end_time\":0}],\"id\":\"5a327cbdb05a2133678b5d3e\"}}}"); + + var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); + var result = await sut.GetHomeStatus(homeId); + + httpTest.ShouldHaveCalled("https://api.netatmo.com/api/homestatus") + .WithVerb(HttpMethod.Post) + .WithOAuthBearerToken(accessToken) + .WithContentType("application/json") + .WithRequestJson(new GetHomeStatusRequest { HomeId = homeId }) + .Times(1); + + result.Body.Should().BeOfType(); + result.Body.Home.Modules[0].WifiStatus.Should().Be(WifiStrengthEnum.Good); + result.Body.Home.Modules[0].RfStatus.Should().Be(RfStrengthEnum.Low); + + result.Body.Home.Modules[1].WifiStatus.Should().Be(WifiStrengthEnum.Undefined); + result.Body.Home.Modules[1].BatteryStatus.Should().Be(BatteryLevelEnum.Full); + + result.Body.Home.Modules[2].BatteryStatus.Should().Be(BatteryLevelEnum.High); + } + + [Fact] + public async Task GetRoomMeasure_Should_Return_TemperatureSteps() + { + var parameters = new GetRoomMeasureParameters + { + HomeId = "5a327cbdb05a2133678b5d3e", RoomId = "2255031728", Scale = Scale.Max, Type = ThermostatMeasurementType.Temperature + }; + + httpTest.RespondWith( + "{\"body\":[{\"beg_time\":1513259100,\"step_time\":1800,\"value\":[[27.9],[27.1],[26.2],[25.4],[25.8],[26.2],[26.7],[26.9],[27],[27.1],[27.2],[27],[26.8],[26.6],[26.5],[26.3],[26.3],[26.3],[26.2],[26.2],[26.2],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26],[26],[26.1],[26],[26],[26],[26],[26],[25.9],[24.8],[24],[23.6],[23.5],[23.2],[23],[22.9],[22.7],[22.5],[22.4],[22.4],[22.6],[22.8],[23.1],[23.2],[23.4],[23.4],[23.3],[23.1],[22.9],[22.5],[22.2],[21.9],[21.6],[21.6],[21.4],[21.2],[21.1],[21],[20.9],[20.8],[20.7],[20.7],[20.6],[20.6],[20.6],[20.5],[20.5],[20.5],[20.4],[20.4],[20.4],[20.4],[20.4],[20.3],[20.3],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.3],[20.3],[20.3],[20.3],[20.2],[20.2],[20.1],[20],[20],[19.9],[19.8],[19.8],[19.8],[19.7],[19.7],[19.7],[19.6],[19.9],[20.2],[20.6],[20.6],[20.7],[20.6],[20.7],[20.7],[20.7],[20.8],[20.7],[20.8],[20.7],[20.8],[20.5],[20.2],[20],[19.9],[19.7],[19.6],[19.5],[19.5],[19.4],[19.4],[19.4],[19.5],[19.5],[19.6],[19.6],[19.6],[19.7],[19.7],[19.7],[19.7],[19.7],[19.7],[19.6],[19.6],[19.5],[19.4],[19.4],[19.3],[19.3],[19.3],[19.3],[19.2],[19.2],[19.3],[20],[20.6],[20.8],[20.9],[20.8],[20.9],[21],[20.8],[20.9],[20.9],[20.7],[20.8],[20.8],[20.7],[20.4],[20.2],[20],[19.9],[19.7],[19.6],[19.6],[19.5],[19.7],[20.3],[20.6],[21],[21.3],[21.7],[21.9],[21.7],[21.6],[21.6],[21.5],[21.6],[21.9],[22.1],[22],[22],[22.1],[22.2],[22.3],[22.2],[21.9],[21.5],[21.1],[20.7],[20.5],[20.3],[20.4],[20.6],[20.7],[20.7],[20.8],[20.7],[20.8],[20.7],[20.8],[20.7],[20.8],[20.7],[20.8],[20.8],[20.5],[20.2],[20],[19.9],[19.7],[19.7],[19.6],[19.5],[19.7],[20.2],[20.6],[21],[21.4],[21.7],[21.7],[21.5],[21.2],[21],[21],[21.2],[21.5],[21.8],[22.2],[22.2],[22.3],[22.6],[23.4],[23.8],[24.2],[24.4],[24.4],[24.4],[24.5],[24.5],[24.5],[24.6],[24.6],[24.6],[24.6],[24.6],[24.7],[24.7],[24.7],[24.7],[24.8],[24.8],[24.8],[24.9],[24.9],[24.9],[25],[25],[25.1],[25.1],[25.1],[25.2],[25.2],[25.3],[25.6],[25.9],[26.1],[26.4],[26.5],[26.4],[26.3],[26.2],[26.3],[26.4],[26.5],[26.7],[26.8],[26.7],[26.9],[27],[27],[26.7],[26.6],[26.5],[26.3],[26.2],[26.1],[26],[26],[26],[26],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[26],[26],[26],[26],[26],[26.1],[26.1],[25.2],[23.9],[23.2],[24.1],[25.1],[25.9],[26.3],[26.6],[26.6],[26.2],[25.7],[25],[24.4],[25.1],[25.7],[26.2],[26.3],[26.1],[25.9],[25.2],[24],[22.9],[21.9],[21],[20.2],[19.6],[19.3],[19.1],[19],[18.9],[18.8],[18.7],[18.6],[18.5],[18.4],[18.3],[18.2],[18.1],[18],[17.9],[17.8],[17.6],[17.4],[17.3],[17.1],[17],[17],[17.3],[18.2],[20.2],[21.9],[23.2],[24.1],[24.8],[25.2],[24.8],[23.9],[24.3],[25],[25.6],[26],[26.2],[26.3],[26.4],[26.4],[26.5],[26.5],[26.4],[26.3],[26.2],[26.1],[26],[25.9],[25.9],[25.9],[25.8],[25.8],[25.8],[25.8],[25.8],[25.8],[25.8],[25.8],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[25.9],[26],[26],[26],[26],[26],[26],[26],[26.1],[26.1],[26.1],[26.2],[26.2],[26.2],[26.2],[26.2],[26.3],[26.3],[26.3],[26.3],[26.2],[26.2],[26.2],[26.2],[26.2],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.3],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.2],[26.3],[26.3],[26.4],[26.4],[26.5],[26.4],[26.4],[26.3],[26.3],[26.3],[26.3],[26.2],[26.2],[26.2],[26.2],[26.2],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26.1],[26],[26],[25.9],[25.9],[25.8],[25.8],[25.8],[25.7],[25.7],[25.7],[25.7],[25.7],[25.7],[25.7],[25.8],[25.9],[26],[26],[24.8],[23.8],[24.4],[24.9],[25.3],[25.8],[26.1],[26.4],[26.6],[26.7],[26.7],[26.8],[26.9],[26.9],[27.1],[27.2],[27.3],[27.3],[27.3],[27.3],[27.2],[27.1],[27],[26.9],[26.8],[26.7],[26.6],[26.5],[26.5],[26.4],[26.4],[26.3],[26.2],[26.1],[26.1],[26],[26],[25.9],[25.9],[25.9],[25.8],[25.8],[25.8],[25.9],[26],[26.1],[26.2],[26.2],[26.3],[25.1],[24.9],[25.2],[25.6],[26],[26.4],[26.6],[26.7],[26.7],[26.7],[26.6],[26.6],[26.7],[26.7],[26.9],[26.6],[26.5],[26.6],[26.7],[26.7],[26.5],[26.5],[26.4],[26.4],[26.4],[26.4],[26.4],[26.3],[26.3],[26.2],[26.2],[26.1],[26.1],[26],[26],[25.9],[25.9],[25.9],[25.8],[25.8],[25.8],[25.8],[25.8],[25.8],[25.9],[25.9],[25.9],[25.9],[26],[26.1],[25.9],[24.8],[25.2],[25.7],[26.3],[26.6],[26.7],[26.8],[26.8],[26.7],[26.9],[27],[27.1],[27.1],[26.8],[26.3],[25.4],[24.6],[23.8],[23.2],[22.6],[22.2],[21.9],[21.6],[21.5],[21.4],[21.3],[21.2],[21.1],[21],[21],[20.9],[20.8],[20.8],[20.7],[20.7],[20.6],[20.6],[20.6],[20.5],[20.5],[20.4],[20.4],[20.3],[20.2],[20.2],[20.2],[20.3],[20.5],[20.7],[20.9],[21.1],[21.2],[21.3],[21.3],[21.3],[21.3],[21.3],[21.4],[21.5],[21.5],[21.6],[21.6],[21.6],[21.6],[21.6],[21.4],[21],[20.8],[20.6],[20.4],[20.3],[20.2],[20.4],[20.5],[20.5],[20.5],[20.5],[20.5],[20.5],[20.6],[20.5],[20.6],[20.5],[20.6],[20.5],[20.6],[20.4],[20.3],[20.3],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.3],[20.3],[20.3],[20.4],[20.4],[20.5],[20.5],[20.4],[20.4],[20.4],[20.4],[20.4],[20.4],[20.3],[20.3],[20.3],[20.3],[20.3],[20.2],[20.2],[20.2],[20.2],[20.2],[20.2],[20.5],[20.7],[20.7],[20.8],[20.7],[20.7],[20.7],[20.8],[20.8],[20.7],[20.8],[20.7],[20.8],[20.7],[20.5],[20.4],[20.3],[20.2],[20.2],[20.1],[20.1],[20.1],[20.1],[20.1],[20.1],[20.1],[20.1],[20.1],[20.2],[20.2],[20.3],[20.4],[20.3],[20.3],[20.3],[20.2],[20.2],[20.1],[20],[20],[19.9],[19.9],[19.9],[19.9],[19.8],[19.8],[19.8],[19.8],[20],[20.3],[20.7],[20.7],[20.8],[20.7],[20.8],[20.7],[20.8],[20.7],[20.8],[20.7],[20.8],[20.7],[20.4],[20.1],[20],[19.9],[19.7],[19.7],[19.5],[19.5],[19.5],[19.4],[19.4],[19.4],[19.4],[19.4],[19.4],[19.4],[19.4],[19.5],[19.7],[19.7],[19.6],[19.6],[19.5],[19.5],[19.5],[19.4],[19.4],[19.4],[19.3],[19.3],[19.3],[19.3],[19.3],[19.4],[20.2],[20.7],[20.9],[20.7],[20.8],[20.8],[20.7],[20.8],[20.7],[20.7],[20.8],[20.7],[20.8],[20.7],[20.4],[20.1],[19.8],[19.7],[19.6],[19.5],[19.4],[19.4],[19.5],[19.9],[20.5],[20.8],[21],[21.3],[21.3],[21.1],[20.9],[20.9],[21.2],[21.5],[21.8],[22.1],[22.2],[22.3],[22.3],[22.4],[22.4],[22.1],[21.7],[21.3],[21],[20.7],[20.5],[20.4],[20.6],[20.7],[20.7],[20.9],[20.8],[20.8],[20.8],[20.8],[20.9],[20.8],[20.8],[20.8],[20.8],[20.9],[20.6],[20.4],[20.3],[20.2],[20.1],[20.1],[20],[19.9],[20.2],[20.7],[21.2],[21.7],[21.9],[22],[21.9],[21.6],[21.5],[21.6],[21.8],[22]]},{\"beg_time\":1514992500,\"step_time\":1800,\"value\":[[22.8],[22.9],[22.8],[22.7],[22.8],[22.8],[22.7],[22.3],[21.8],[21.4],[21.1],[20.8],[20.6],[20.6],[20.8],[20.8],[20.9],[20.8],[20.9],[20.9],[20.9],[20.9],[20.9],[20.9],[20.9],[20.9],[20.9],[20.7],[20.6],[20.4],[20.4],[20.3],[20.3],[20.3],[20.3],[20.6],[21.2],[21.4],[21.6],[21.8],[22.1],[22.2],[22],[21.9],[21.9],[22],[22.3],[22.5],[22.6],[22.7],[22.8],[22.8],[22.9],[22.6],[22.3],[21.7],[21.4],[21.1],[20.9],[20.7],[20.5],[20.7]]}],\"status\":\"ok\",\"time_exec\":0.79246497154236,\"time_server\":1518023284}"); + + var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); + var result = await sut.GetRoomMeasure(parameters); + + httpTest.ShouldHaveCalled("https://api.netatmo.com/api/getroommeasure") + .WithVerb(HttpMethod.Post) + .WithOAuthBearerToken(accessToken) + .WithContentType("application/json") + .WithRequestJson(new GetRoomMeasureRequest { HomeId = parameters.HomeId, RoomId = parameters.RoomId, Scale = parameters.Scale.Value, Type = parameters.Type.Value }) + .Times(1); + + result.Body[0].BeginAt.Should().Be(Instant.FromDateTimeUtc(DateTime.SpecifyKind(new DateTime(2017, 12, 14, 13, 45, 0), DateTimeKind.Utc))); + result.Body.Length.Should().Be(2); + result.Body[0].Values[0][0].Should().Be(27.9); + result.Body[0].Values[1][0].Should().Be(27.1); + } + + [Fact] + public void GetRoomMeasure_With_Bad_Type_Should_Throw_ArgumentException() + { + var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); + Func actTemperatureStep = () => sut.GetRoomMeasure( + new GetRoomMeasureParameters { HomeId = "5a327cbdb05a2133678b5d3e", RoomId = "2255031728", Scale = Scale.Max, Type = ThermostatMeasurementType.Temperature }); + + Func actDateTemperatureStep = async () => + { + await sut.GetRoomMeasure( + new GetRoomMeasureParameters + { + HomeId = "5a327cbdb05a2133678b5d3e", RoomId = "2255031728", Scale = Scale.OneMonth, Type = ThermostatMeasurementType.DateMinTemp + }); + }; + + actTemperatureStep.Should().ThrowAsync().WithMessage("TemperatureStep should be used with a temperature measurement"); + actDateTemperatureStep.Should().ThrowAsync().WithMessage("DateTemperatureStep should be used with a date of temperature measurement"); + } + + [Fact] + public async Task RenameHomeSchedule_Should_Return_Expected_Result() + { + var homeId = "5a327cbdb05a2133678b5d3e"; + var scheduleId = "5a327cbdb05a2133678b5d3f"; + var name = "Cat schedule"; + httpTest.RespondWithJson(new DataResponse("ok", 0.036107063293457, Instant.FromUnixTimeSeconds(1518023467))); + + var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); + await sut.RenameHomeSchedule(homeId, scheduleId, name); + + httpTest.ShouldHaveCalled("https://api.netatmo.com/api/renamehomeschedule") + .WithVerb(HttpMethod.Post) + .WithOAuthBearerToken(accessToken) + .WithContentType("application/json") + .WithRequestJson(new RenameHomeScheduleRequest { HomeId = homeId, ScheduleId = scheduleId, Name = name }) + .Times(1); + } + + [Fact] + public async Task SetRoomThermPoint_Should_Return_Expected_Result() + { + var homeId = "5a327cbdb05a2133678b5d3e"; + var roomId = "2255031728"; + var mode = "schedule"; + httpTest.RespondWithJson(new DataResponse("ok", 0.036107063293457, Instant.FromUnixTimeSeconds(1518023467))); + + var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); + await sut.SetRoomThermPoint(homeId, roomId, mode); + + httpTest.ShouldHaveCalled("https://api.netatmo.com/api/setroomthermpoint") + .WithVerb(HttpMethod.Post) + .WithOAuthBearerToken(accessToken) + .WithContentType("application/json") + .WithRequestJson(new SetRoomThermpointRequest { HomeId = homeId, RoomId = roomId, Mode = mode }) + .Times(1); + } + + [Fact] + public async Task SetThermMode_Should_Return_Expected_Result() + { + var homeId = "5a327cbdb05a2133678b5d3e"; + var mode = "schedule"; + httpTest.RespondWithJson(new DataResponse("ok", 0.036107063293457, Instant.FromUnixTimeSeconds(1518023467))); + + var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); + await sut.SetThermMode(homeId, mode); + + httpTest.ShouldHaveCalled("https://api.netatmo.com/api/setthermmode") + .WithVerb(HttpMethod.Post) + .WithOAuthBearerToken(accessToken) + .WithContentType("application/json") + .WithRequestJson(new SetThermModeRequest { HomeId = homeId, Mode = mode }) + .Times(1); + } + + [Fact] + public async Task SwitchHomeSchedule_Should_Return_Expected_Result() + { + var homeId = "5a327cbdb05a2133678b5d3e"; + var scheduleId = "5a327cbdb05a2133678b5d3f"; + httpTest.RespondWithJson(new DataResponse("ok", 0.036107063293457, Instant.FromUnixTimeSeconds(1518023467))); + + var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); + await sut.SwitchHomeSchedule(homeId, scheduleId); + + httpTest.ShouldHaveCalled("https://api.netatmo.com/api/switchhomeschedule") + .WithVerb(HttpMethod.Post) + .WithOAuthBearerToken(accessToken) + .WithContentType("application/json") + .WithRequestJson(new SwitchHomeScheduleRequest { HomeId = homeId, ScheduleId = scheduleId }) + .Times(1); + } + + [Fact] + public async Task SyncHomeSchedule_Should_Return_Expected_Result() + { + var parameters = new SyncHomeScheduleRequest("5a327cbdb05a2133678b5d3e", "5a327cbdb05a2133678b5d3f", 14, 16); + httpTest.RespondWithJson(new DataResponse("ok", 0.036107063293457, Instant.FromUnixTimeSeconds(1518023467))); + + var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); + await sut.SyncHomeSchedule(parameters); + + httpTest.ShouldHaveCalled("https://api.netatmo.com/api/synchomeschedule") + .WithVerb(HttpMethod.Post) + .WithOAuthBearerToken(accessToken) + .WithContentType("application/json") + .WithRequestJson( + new SyncHomeScheduleRequest(parameters.HomeId, parameters.ScheduleId, parameters.HgTemp, parameters.AwayTemp, Array.Empty(), Array.Empty())) + .Times(1); + } + + [Theory] + [ClassData(typeof(GetRoomMeasureArgumentExceptionData))] + public void GetRoomMeasure_Should_Throw_ArgumentException(GetRoomMeasureParameters parameters, string exceptionMessage) + { + var sut = new Netatmo.EnergyClient("https://api.netatmo.com/", credentialManagerMock.Object); + Func act = () => sut.GetRoomMeasure(parameters); + + act.Should().ThrowAsync().WithMessage(exceptionMessage); + } +} \ No newline at end of file diff --git a/src/Netatmo.Tests/Netatmo.Tests.csproj b/tests/Netatmo.Tests/Netatmo.Tests.csproj similarity index 53% rename from src/Netatmo.Tests/Netatmo.Tests.csproj rename to tests/Netatmo.Tests/Netatmo.Tests.csproj index 2f8ae39..67385c3 100644 --- a/src/Netatmo.Tests/Netatmo.Tests.csproj +++ b/tests/Netatmo.Tests/Netatmo.Tests.csproj @@ -1,7 +1,8 @@  - net5.0 + net6.0 enable + enable False False True @@ -14,15 +15,24 @@ - - - - - - + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - + + + + + + + diff --git a/tests/Netatmo.Tests/WeatherClient.cs b/tests/Netatmo.Tests/WeatherClient.cs new file mode 100644 index 0000000..7e35883 --- /dev/null +++ b/tests/Netatmo.Tests/WeatherClient.cs @@ -0,0 +1,58 @@ +using Flurl.Http.Testing; +using Netatmo.Enums; +using Netatmo.Models.Client.Weather; +using Netatmo.Models.Client.Weather.StationsData.DashboardData; +using NodaTime; + +namespace Netatmo.Tests; + +public class WeatherClient : IDisposable +{ + private readonly HttpTest httpTest; + + public WeatherClient() + { + httpTest = new HttpTest(); + httpTest.Configure(Configuration.ConfigureRequest); + } + + public void Dispose() + { + httpTest.Dispose(); + } + + [Fact] + public async Task GetStationsData_Should_Return_DataResponse_With_StationsData() + { + var accessToken = "Super-Access-Token"; + var credentialManagerMock = new Mock(); + credentialManagerMock.Setup(x => x.AccessToken).Returns(accessToken); + + httpTest.RespondWith( + "{\"body\":{\"devices\":[{\"_id\":\"70:ee:50:2c:xx:xx\",\"last_status_store\":1523889831,\"modules\":[{\"_id\":\"02:00:00:2c:xx:xx\",\"type\":\"NAModule1\",\"last_message\":1523889829,\"last_seen\":1523889816,\"dashboard_data\":{\"Temperature\":24.3,\"temp_trend\":\"stable\",\"Humidity\":40,\"time_utc\":1523889765,\"date_max_temp\":1523885867,\"date_min_temp\":1523851467,\"min_temp\":21.4,\"max_temp\":24.7},\"data_type\":[\"Temperature\",\"Humidity\"],\"module_name\":\"Exterieur\",\"last_setup\":1518622000,\"battery_vp\":5924,\"battery_percent\":97,\"rf_status\":9,\"firmware\":46}],\"place\":{\"altitude\":-55.681362,\"city\":\"Puteaux\",\"country\":\"FR\",\"timezone\":\"Europe\\/Paris\",\"location\":[2.2389,48.8834]},\"station_name\":\"Test\",\"type\":\"NAMain\",\"dashboard_data\":{\"Temperature\":23.7,\"temp_trend\":\"down\",\"Humidity\":42,\"AbsolutePressure\":1033.2,\"Pressure\":1026.4,\"pressure_trend\":\"up\",\"Noise\":53,\"CO2\":1099,\"time_utc\":1523889815,\"date_max_temp\":1523885587,\"date_min_temp\":1523850877,\"min_temp\":21,\"max_temp\":24.4},\"data_type\":[\"Temperature\",\"CO2\",\"Humidity\",\"Noise\",\"Pressure\"],\"co2_calibrating\":false,\"date_setup\":1518621999,\"last_setup\":1518621999,\"module_name\":\"Indoor\",\"firmware\":134,\"last_upgrade\":1518622001,\"wifi_statuswifi_status\":47,\"friend_users\":[\"5a856f288af105312c8xxxxx\"]}],\"user\":{\"mail\":\"example@domain.com\",\"administrative\":{\"lang\":\"fr-FR\",\"reg_locale\":\"en-FR\",\"country\":\"FR\",\"unit\":0,\"windunit\":0,\"pressureunit\":0,\"feel_like_algo\":0}}},\"status\":\"ok\",\"time_exec\":0.075635195,\"time_server\":1523890283}"); + + var sut = new Netatmo.WeatherClient("https://api.netatmo.com/", credentialManagerMock.Object); + var result = await sut.GetStationsData(); + + httpTest.ShouldHaveCalled("https://api.netatmo.com/api/getstationsdata") + .WithVerb(HttpMethod.Post) + .WithOAuthBearerToken(accessToken) + .WithContentType("application/json") + .WithRequestJson(new GetStationsDataRequest()) + .Times(1); + + result.Body.Should().BeOfType(); + result.Body.Devices[0].DashboardData.Noise.Should().Be(53); + result.Body.Devices[0].WifiStrength.Should().Be(WifiStrengthEnum.Good); + result.Body.Devices[0].Modules[0].GetDashboardData().HumidityPercent.Should().Be(40); + result.Body.Devices[0] + .Modules[0] + .Invoking(y => y.GetDashboardData()) + .Should() + .Throw() + .WithMessage("OutdoorDashBoardData should be expected"); + result.Body.Devices[0].Modules[0].RfStrength.Should().Be(RfStrengthEnum.FullSignal); + result.Body.Devices[0].Modules[0].BatteryStatus.Should().Be(BatteryLevelEnum.Full); + result.Body.Devices[0].Place.Timezone.Should().Be(DateTimeZoneProviders.Tzdb["Europe/Paris"]); + } +} \ No newline at end of file diff --git a/tests/TestApp/Program.cs b/tests/TestApp/Program.cs new file mode 100644 index 0000000..ad8a8ea --- /dev/null +++ b/tests/TestApp/Program.cs @@ -0,0 +1,89 @@ +using Flurl.Http; +using Flurl.Util; +using Netatmo; +using Netatmo.Models.Client.Energy; +using Netatmo.Models.Client.Energy.RoomMeasure; +using Newtonsoft.Json; +using NodaTime; + +JsonConvert.DefaultSettings = Configuration.JsonSerializer; + +IClient client = new Client( + SystemClock.Instance, + "https://api.netatmo.com/", + Environment.GetEnvironmentVariable("NETATMO_CLIENT_ID"), + Environment.GetEnvironmentVariable("NETATMO_CLIENT_SECRET")); + +await client.GenerateToken( + Environment.GetEnvironmentVariable("NETATMO_USERNAME"), + Environment.GetEnvironmentVariable("NETATMO_PASSWORD"), + new[] + { + Scope.CameraAccess, + Scope.CameraRead, + Scope.CameraWrite, + Scope.HomecoachRead, + Scope.PresenceAccess, + Scope.PresenceRead, + Scope.StationRead, + Scope.StationWrite, + Scope.ThermostatRead + }); + +var token = client.CredentialManager.CredentialToken; + +Console.WriteLine($"Token : {token.AccessToken}"); + +Console.WriteLine("Stations data :"); +var stationsData = await client.Weather.GetStationsData(); +Console.WriteLine(JsonConvert.SerializeObject(stationsData, Formatting.Indented)); + +Console.WriteLine("Energy Homes data :"); +var homesData = await client.Energy.GetHomesData(); +Console.WriteLine(JsonConvert.SerializeObject(homesData, Formatting.Indented)); + +Console.WriteLine("Energy Homes data :"); +foreach (var home in homesData.Body.Homes) +{ + Console.WriteLine(home.Name); + var homeStatus = await client.Energy.GetHomeStatus(home.Id); + Console.WriteLine(JsonConvert.SerializeObject(homeStatus, Formatting.Indented)); + + Console.WriteLine("Energy room measure :"); + foreach (var room in home.Rooms) + { + if (room.ModuleIds == null || !room.ModuleIds.Any()) + { + continue; + } + + Console.WriteLine(room.Name); + var parameters = new GetRoomMeasureParameters + { + HomeId = home.Id, + RoomId = room.Id, + Scale = Scale.Max, + Type = ThermostatMeasurementType.Temperature, + BeginAt = SystemClock.Instance.GetCurrentInstant().Plus(Duration.FromDays(-1)), + EndAt = SystemClock.Instance.GetCurrentInstant() + }; + + try + { + var roomMeasure = await client.Energy.GetRoomMeasure(parameters); + Console.WriteLine(JsonConvert.SerializeObject(roomMeasure, Formatting.Indented)); + } + catch (FlurlHttpException exception) + { + var error = await exception.GetResponseStringAsync(); + Console.WriteLine($"exception : {error}"); + } + } +} + +Console.WriteLine("RefreshToken :"); +Thread.Sleep(9000); +await client.RefreshToken(); +var newToken = client.CredentialManager.CredentialToken; +Console.WriteLine($"Old token expires at : {token.ExpiresAt.ToInvariantString()}"); +Console.WriteLine($"New token expires at : {newToken.ExpiresAt.ToInvariantString()}"); \ No newline at end of file diff --git a/src/TestApp/TestApp.csproj b/tests/TestApp/TestApp.csproj similarity index 70% rename from src/TestApp/TestApp.csproj rename to tests/TestApp/TestApp.csproj index 1e51bca..588b6cf 100644 --- a/src/TestApp/TestApp.csproj +++ b/tests/TestApp/TestApp.csproj @@ -1,8 +1,9 @@ Exe - net5.0;netstandard2.1;netstandard2.0;netcoreapp3.1 - latest + net6.0 + enable + enable false @@ -13,6 +14,6 @@ - +