├── .gitattributes ├── .github └── workflows │ ├── docs.yml │ └── release.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── TPLinkSmartDevices.sln ├── docs ├── docs │ ├── about.md │ ├── assets │ │ └── icon.png │ ├── docs │ │ ├── data │ │ │ ├── hsv.md │ │ │ ├── light-details.md │ │ │ └── power.md │ │ ├── devices │ │ │ ├── bulb.md │ │ │ ├── device.md │ │ │ ├── dimmer.md │ │ │ ├── multi-plug.md │ │ │ ├── plug.md │ │ │ └── smartmeter-plug.md │ │ ├── discovery.md │ │ └── index.md │ ├── getting-started.md │ ├── index.md │ ├── schedule.md │ └── timer.md ├── mkdocs.yml └── site │ ├── 404.html │ ├── about │ └── index.html │ ├── assets │ ├── icon.png │ ├── images │ │ └── favicon.png │ ├── javascripts │ │ ├── bundle.f9edbbd5.min.js │ │ ├── bundle.f9edbbd5.min.js.map │ │ ├── lunr │ │ │ ├── min │ │ │ │ ├── lunr.ar.min.js │ │ │ │ ├── lunr.da.min.js │ │ │ │ ├── lunr.de.min.js │ │ │ │ ├── lunr.du.min.js │ │ │ │ ├── lunr.es.min.js │ │ │ │ ├── lunr.fi.min.js │ │ │ │ ├── lunr.fr.min.js │ │ │ │ ├── lunr.hu.min.js │ │ │ │ ├── lunr.it.min.js │ │ │ │ ├── lunr.ja.min.js │ │ │ │ ├── lunr.jp.min.js │ │ │ │ ├── lunr.multi.min.js │ │ │ │ ├── lunr.nl.min.js │ │ │ │ ├── lunr.no.min.js │ │ │ │ ├── lunr.pt.min.js │ │ │ │ ├── lunr.ro.min.js │ │ │ │ ├── lunr.ru.min.js │ │ │ │ ├── lunr.stemmer.support.min.js │ │ │ │ ├── lunr.sv.min.js │ │ │ │ ├── lunr.tr.min.js │ │ │ │ └── lunr.vi.min.js │ │ │ └── tinyseg.min.js │ │ ├── vendor.c3dc8c49.min.js │ │ ├── vendor.c3dc8c49.min.js.map │ │ └── worker │ │ │ ├── search.8e2cddea.min.js │ │ │ └── search.8e2cddea.min.js.map │ └── stylesheets │ │ ├── main.947af8d5.min.css │ │ ├── main.947af8d5.min.css.map │ │ ├── palette.7f672a1f.min.css │ │ └── palette.7f672a1f.min.css.map │ ├── docs │ ├── data │ │ ├── hsv │ │ │ └── index.html │ │ ├── light-details │ │ │ └── index.html │ │ └── power │ │ │ └── index.html │ ├── devices │ │ ├── bulb │ │ │ └── index.html │ │ ├── device │ │ │ └── index.html │ │ ├── multi-plug │ │ │ └── index.html │ │ ├── plug │ │ │ └── index.html │ │ └── smartmeter-plug │ │ │ └── index.html │ ├── discovery │ │ └── index.html │ └── index.html │ ├── getting-started │ └── index.html │ ├── index.html │ ├── search │ └── search_index.json │ ├── sitemap.xml │ └── sitemap.xml.gz └── tplink-smartdevices ├── Data ├── BoolConverter.cs ├── BulbHSV.cs ├── CountDownRule │ ├── CountDownRule.cs │ └── ICountDown.cs ├── DimmerOptions.cs ├── LightDetails.cs ├── PowerData.cs └── Schedule │ ├── ISchedule.cs │ ├── Schedule.cs │ ├── TimeOption.cs │ └── Weekdays.cs ├── Devices ├── TPLinkSmartBulb.cs ├── TPLinkSmartDevice.cs ├── TPLinkSmartDimmer.cs ├── TPLinkSmartMeterPlug.cs ├── TPLinkSmartMultiPlug.cs └── TPLinkSmartPlug.cs ├── Events └── DeviceFoundEventArgs.cs ├── Messaging ├── IMessageCache.cs ├── ManualMessageCache.cs ├── NoMessageCache.cs ├── SmartHomeProtocolEncoder.cs ├── SmartHomeProtocolMessage.cs └── TimeGatedMessageCache.cs ├── TPLinkDiscovery.cs └── TPLinkSmartDevices.csproj /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Publish docs on GitHub Pages 2 | on: 3 | push: 4 | branches: 5 | - master 6 | 7 | jobs: 8 | build: 9 | name: Deploy docs 10 | runs-on: windows-latest 11 | steps: 12 | - name: Checkout master 13 | uses: actions/checkout@v1 14 | 15 | - name: build 16 | working-directory: docs 17 | run: | 18 | pip install mkdocs 19 | pip install mkdocs-material 20 | mkdocs build 21 | 22 | - name: deploy 23 | uses: peaceiris/actions-gh-pages@v3 24 | with: 25 | github_token: ${{ secrets.GITHUB_TOKEN }} 26 | publish_dir: ./docs/site 27 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | build: 10 | runs-on: windows-latest 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v2 14 | 15 | - name: Setup .NET 16 | uses: actions/setup-dotnet@v1 17 | with: 18 | dotnet-version: 3.1.x 19 | 20 | - name: Build 21 | run: dotnet build --configuration Release 22 | 23 | - name: Get Version Number 24 | id: get_version_number 25 | run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} 26 | shell: bash 27 | 28 | - name: Pack Assets 29 | id: pack_assets 30 | run: | 31 | Compress-Archive tplink-smartdevices.dll tplink-smartdevices${{ steps.get_version_number.outputs.VERSION }}.zip 32 | working-directory: tplink-smartdevices/bin/Release/netstandard2.0 33 | 34 | - name: Create Release 35 | id: create_release 36 | uses: actions/create-release@v1 37 | env: 38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 39 | with: 40 | tag_name: ${{ github.ref }} 41 | release_name: Release ${{ steps.get_version_number.outputs.VERSION }} 42 | body: | 43 | Changes in this Release 44 | - see [Changelog](https://github.com/CodeBardian/tplink-smartdevices-netstandard/blob/master/CHANGELOG.md) 45 | draft: false 46 | prerelease: false 47 | 48 | - name: Upload Release Asset 49 | id: upload-release-asset 50 | uses: actions/upload-release-asset@v1 51 | env: 52 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 53 | with: 54 | upload_url: ${{ steps.create_release.outputs.upload_url }} 55 | asset_path: tplink-smartdevices/bin/Release/netstandard2.0/tplink-smartdevices${{ steps.get_version_number.outputs.VERSION }}.zip 56 | asset_name: tplink-smartdevices${{ steps.get_version_number.outputs.VERSION }}.zip 57 | asset_content_type: application/zip 58 | 59 | - name: Pack 60 | run: dotnet pack --configuration Release 61 | 62 | - name: Publish Nuget 63 | run: dotnet nuget push "*.nupkg" -s https://api.nuget.org/v3/index.json -k ${{ secrets.NUGET_KEY }} 64 | working-directory: tplink-smartdevices/bin/Release 65 | 66 | 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | artifacts/ 58 | 59 | # StyleCop 60 | StyleCopReport.xml 61 | 62 | # Files built by Visual Studio 63 | *_i.c 64 | *_p.c 65 | *_h.h 66 | *.ilk 67 | *.meta 68 | *.obj 69 | *.iobj 70 | *.pch 71 | *.pdb 72 | *.ipdb 73 | *.pgc 74 | *.pgd 75 | *.rsp 76 | *.sbr 77 | *.tlb 78 | *.tli 79 | *.tlh 80 | *.tmp 81 | *.tmp_proj 82 | *_wpftmp.csproj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | *.VC.db 103 | *.VC.VC.opendb 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | *.sap 110 | 111 | # Visual Studio Trace Files 112 | *.e2e 113 | 114 | # TFS 2012 Local Workspace 115 | $tf/ 116 | 117 | # Guidance Automation Toolkit 118 | *.gpState 119 | 120 | # ReSharper is a .NET coding add-in 121 | _ReSharper*/ 122 | *.[Rr]e[Ss]harper 123 | *.DotSettings.user 124 | 125 | # JustCode is a .NET coding add-in 126 | .JustCode 127 | 128 | # TeamCity is a build add-in 129 | _TeamCity* 130 | 131 | # DotCover is a Code Coverage Tool 132 | *.dotCover 133 | 134 | # AxoCover is a Code Coverage Tool 135 | .axoCover/* 136 | !.axoCover/settings.json 137 | 138 | # Visual Studio code coverage results 139 | *.coverage 140 | *.coveragexml 141 | 142 | # NCrunch 143 | _NCrunch_* 144 | .*crunch*.local.xml 145 | nCrunchTemp_* 146 | 147 | # MightyMoose 148 | *.mm.* 149 | AutoTest.Net/ 150 | 151 | # Web workbench (sass) 152 | .sass-cache/ 153 | 154 | # Installshield output folder 155 | [Ee]xpress/ 156 | 157 | # DocProject is a documentation generator add-in 158 | DocProject/buildhelp/ 159 | DocProject/Help/*.HxT 160 | DocProject/Help/*.HxC 161 | DocProject/Help/*.hhc 162 | DocProject/Help/*.hhk 163 | DocProject/Help/*.hhp 164 | DocProject/Help/Html2 165 | DocProject/Help/html 166 | 167 | # Click-Once directory 168 | publish/ 169 | 170 | # Publish Web Output 171 | *.[Pp]ublish.xml 172 | *.azurePubxml 173 | # Note: Comment the next line if you want to checkin your web deploy settings, 174 | # but database connection strings (with potential passwords) will be unencrypted 175 | *.pubxml 176 | *.publishproj 177 | 178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 179 | # checkin your Azure Web App publish settings, but sensitive information contained 180 | # in these scripts will be unencrypted 181 | PublishScripts/ 182 | 183 | # NuGet Packages 184 | *.nupkg 185 | # The packages folder can be ignored because of Package Restore 186 | **/[Pp]ackages/* 187 | # except build/, which is used as an MSBuild target. 188 | !**/[Pp]ackages/build/ 189 | # Uncomment if necessary however generally it will be regenerated when needed 190 | #!**/[Pp]ackages/repositories.config 191 | # NuGet v3's project.json files produces more ignorable files 192 | *.nuget.props 193 | *.nuget.targets 194 | 195 | # Microsoft Azure Build Output 196 | csx/ 197 | *.build.csdef 198 | 199 | # Microsoft Azure Emulator 200 | ecf/ 201 | rcf/ 202 | 203 | # Windows Store app package directories and files 204 | AppPackages/ 205 | BundleArtifacts/ 206 | Package.StoreAssociation.xml 207 | _pkginfo.txt 208 | *.appx 209 | 210 | # Visual Studio cache files 211 | # files ending in .cache can be ignored 212 | *.[Cc]ache 213 | # but keep track of directories ending in .cache 214 | !?*.[Cc]ache/ 215 | 216 | # Others 217 | ClientBin/ 218 | ~$* 219 | *~ 220 | *.dbmdl 221 | *.dbproj.schemaview 222 | *.jfm 223 | *.pfx 224 | *.publishsettings 225 | orleans.codegen.cs 226 | 227 | # Including strong name files can present a security risk 228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 229 | #*.snk 230 | 231 | # Since there are multiple workflows, uncomment next line to ignore bower_components 232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 233 | #bower_components/ 234 | 235 | # RIA/Silverlight projects 236 | Generated_Code/ 237 | 238 | # Backup & report files from converting an old project file 239 | # to a newer Visual Studio version. Backup files are not needed, 240 | # because we have git ;-) 241 | _UpgradeReport_Files/ 242 | Backup*/ 243 | UpgradeLog*.XML 244 | UpgradeLog*.htm 245 | ServiceFabricBackup/ 246 | *.rptproj.bak 247 | 248 | # SQL Server files 249 | *.mdf 250 | *.ldf 251 | *.ndf 252 | 253 | # Business Intelligence projects 254 | *.rdl.data 255 | *.bim.layout 256 | *.bim_*.settings 257 | *.rptproj.rsuser 258 | *- Backup*.rdl 259 | 260 | # Microsoft Fakes 261 | FakesAssemblies/ 262 | 263 | # GhostDoc plugin setting file 264 | *.GhostDoc.xml 265 | 266 | # Node.js Tools for Visual Studio 267 | .ntvs_analysis.dat 268 | node_modules/ 269 | 270 | # Visual Studio 6 build log 271 | *.plg 272 | 273 | # Visual Studio 6 workspace options file 274 | *.opt 275 | 276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 277 | *.vbw 278 | 279 | # Visual Studio LightSwitch build output 280 | **/*.HTMLClient/GeneratedArtifacts 281 | **/*.DesktopClient/GeneratedArtifacts 282 | **/*.DesktopClient/ModelManifest.xml 283 | **/*.Server/GeneratedArtifacts 284 | **/*.Server/ModelManifest.xml 285 | _Pvt_Extensions 286 | 287 | # Paket dependency manager 288 | .paket/paket.exe 289 | paket-files/ 290 | 291 | # FAKE - F# Make 292 | .fake/ 293 | 294 | # JetBrains Rider 295 | .idea/ 296 | *.sln.iml 297 | 298 | # CodeRush personal settings 299 | .cr/personal 300 | 301 | # Python Tools for Visual Studio (PTVS) 302 | __pycache__/ 303 | *.pyc 304 | 305 | # Cake - Uncomment if you are using it 306 | # tools/** 307 | # !tools/packages.config 308 | 309 | # Tabs Studio 310 | *.tss 311 | 312 | # Telerik's JustMock configuration file 313 | *.jmconfig 314 | 315 | # BizTalk build output 316 | *.btp.cs 317 | *.btm.cs 318 | *.odx.cs 319 | *.xsd.cs 320 | 321 | # OpenCover UI analysis results 322 | OpenCover/ 323 | 324 | # Azure Stream Analytics local run output 325 | ASALocalRun/ 326 | 327 | # MSBuild Binary and Structured Log 328 | *.binlog 329 | 330 | # NVidia Nsight GPU debugger configuration file 331 | *.nvuser 332 | 333 | # MFractors (Xamarin productivity tool) working folder 334 | .mfractor/ 335 | 336 | # Local History for Visual Studio 337 | .localhistory/ 338 | 339 | # BeatPulse healthcheck temp database 340 | healthchecksdb -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: csharp 2 | solution: TPLinkSmartDevices.sln 3 | mono: latest 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | 3 | ### [2.0.1] - 2022-07-29 4 | 5 | #### Added 6 | 7 | - automatic push to nuget on release ([#dafb5be](https://github.com/CodeBardian/tplink-smartdevices-netstandard/commit/dafb5be)) 8 | 9 | #### Fixed 10 | - exception on sending commands to multiplugs ([#18](https://github.com/CodeBardian/tplink-smartdevices-netstandard/pull/18)) 11 | 12 | ### [2.0.0] - 2021-04-04 13 | 14 | #### Added 15 | 16 | - support for hs220 dimmer switch ([#28556c9](https://github.com/CodeBardian/tplink-smartdevices-netstandard/commits/28556c9)) 17 | - Timers 18 | - Schedules 19 | 20 | #### Changed 21 | - no more `Task.Run` ([#1986900](https://github.com/CodeBardian/tplink-smartdevices-netstandard/commits/1986900)) 22 | 23 | #### Fixed 24 | - exception on retrieving cloud info without internet connection([#96be351e](https://github.com/CodeBardian/tplink-smartdevices-netstandard/commits/6be351e)) 25 | 26 | ### [1.0.4] - 2020-11-16 27 | 28 | #### Added 29 | 30 | - light details of smart bulbs ([#af850dd](https://github.com/CodeBardian/tplink-smartdevices-netstandard/commits/af850dd)) 31 | - apply the four preset light states of smart bulbs ([#03e83c9](https://github.com/CodeBardian/tplink-smartdevices-netstandard/commits/03e83c9) + [#e68bed7](https://github.com/CodeBardian/tplink-smartdevices-netstandard/commits/e68bed7)) 32 | - transition time between light states for smart bulbs ([#db66403](https://github.com/CodeBardian/tplink-smartdevices-netstandard/commits/db66403)) 33 | - support for multi-outlet plugs (HS300, HS107, KP303?) 34 | - ConfigureAwait(false) on awaiting tasks ([#16](https://github.com/CodeBardian/tplink-smartdevices-netstandard/pull/16)) 35 | 36 | #### Changed 37 | - avoid blocking in async methods ([#16](https://github.com/CodeBardian/tplink-smartdevices-netstandard/pull/16)) 38 | - discovery now accepts broadcast address parameter ([#15](https://github.com/CodeBardian/tplink-smartdevices-netstandard/pull/15)) 39 | 40 | #### Fixed 41 | - color changing of kl-130 model ([#9](https://github.com/CodeBardian/tplink-smartdevices-netstandard/pull/16)) 42 | - exception on discovering kl-130 model 43 | - exception on energy stat parsing ([#12](https://github.com/CodeBardian/tplink-smartdevices-netstandard/pull/12)) 44 | 45 | ### [1.0.3] - 2020-08-08 46 | 47 | #### Added 48 | 49 | - access energy stats of hs110 50 | - handle different hardware versions for hs110 51 | 52 | #### Changed 53 | - project now targets .net standard 2.0 54 | - improved emetering commands with error handling 55 | - improved XML documentation for IntelliSense recommendations 56 | 57 | #### Fixed 58 | - location is no longer of type integer 59 | - udp port correctly closing 60 | 61 | ### [1.0.2] - 2020-04-17 62 | 63 | #### Added 64 | 65 | - associate devices to home network 66 | - configure remote access via tplink cloud and kasa 67 | 68 | #### Changed 69 | - more consistent asynchronous code -> all commands to smart devices are now asynchronous 70 | - restructured parts of code for better readability 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tplink-smartdevices-netstandard 2 | .NET Standard 2.0 Library for Discovering and Operating TP-Link Smart Devices

3 | [![Nuget](https://img.shields.io/nuget/v/tplink-smartdevices?style=for-the-badge)](https://www.nuget.org/packages/tplink-smartdevices/) 4 | ![Travis (.org)](https://img.shields.io/travis/CodeBardian/tplink-smartdevices-netstandard?style=for-the-badge) 5 | 6 | This library allows a developer to discover and operate TP-Link Smart Devices from multiple .NET implementations such as .NET Core, Xamarin, .NET Framework and more. 7 | 8 | This project is migrated to .net standard from Anthony Turner's TP-Link Smart Devices SDK:
9 | https://github.com/anthturner/TPLinkSmartDevices
10 | notable changes include: asynchronous operations, more supported devices, better discovery handling, setup functionality (no need for kasa account and app anymore, except for remote control) 11 | 12 | Consult https://github.com/dotnet/standard/blob/master/docs/versions.md to see which .net platform versions can implement this library! 13 | 14 | #### Supported Devices 15 | 16 | | Type | Supported models | Not tested, maybe working | 17 | | ----------------------- | ---------------------------- |---------------------------------- | 18 | | Plug | HS100, HS110, HS300, HS107 | HS105, HS200, KP200/KP303/KP400 | 19 | | Bulb | KL100/KL110/KL130 | KL50/KL60/LB100/LB110/LB120/LB130 | 20 | | Switch | HS220 | | 21 | 22 | > Doesn't include new protocol for firmware version 1.1.0 on HS100 (Hardware Version 4.1) 23 | 24 | ## Usage 25 | Use NuGet package manager to add a reference to this project, for example with dotnet cli: 26 | ``` 27 | > dotnet add package tplink-smartdevices --version 2.0.1 28 | ``` 29 | 30 | #### Setup / First Use 31 | 32 | If your devices are already connected to your Wi-Fi network (e.g through TP-Link provided mobile app Kasa) this step can be skipped. Otherwise you can use the following script to associate your smart devices with your home network: 33 | 34 | ```cs 35 | await new TPLinkDiscovery().Associate("ssid", "password"); 36 | ``` 37 | Note that the device running the program needs to be connected to the network which the tplink devices provide. It should be called "TP-Link_Smart Plug_XXXX" or similar. If you have a brand new plug/bulb this network should automatically appear. Otherwise, hold down the reset button on a plug for about 10 seconds, until its light blinks amber rapidly. For a bulb flip the switch on and off 5 times. Not too quickly though! (About 1 sec per flip). 38 | 39 | ### Discovery 40 | 41 | basic: 42 | ```cs 43 | // Runs in a async Task> 44 | var discoveredDevices = await new TPLinkDiscovery().Discover(); 45 | ``` 46 | 47 | with event handler: 48 | ```cs 49 | TPLinkDiscovery discovery = new TPLinkDiscovery(); 50 | discovery.DeviceFound += delegate { 51 | //Console.WriteLine("Device found: " + e.Device.Alias); 52 | //Log.Debug("DISCOVERY","Device found" + e.Device.Alias); 53 | }; 54 | var discoveredDevices = await discovery.Discover(); 55 | ``` 56 | 57 | ### Power State 58 | ```cs 59 | var smartPlug = await TPLinkSmartPlug.Create("100.10.4.1"); 60 | await smartPlug.SetPoweredOn(true); // Turn on relay 61 | await smartPlug.SetPoweredOn(false); // Turn off relay 62 | ``` 63 | 64 | or after discovery: 65 | ```cs 66 | foreach (var item in discoveredDevices) 67 | { 68 | if (item is TPLinkSmartPlug plug) 69 | { 70 | await plug.SetPoweredOn(true); 71 | } 72 | else if (item is TPLinkSmartBulb bulb) 73 | { 74 | await bulb.SetPoweredOn(true); 75 | } 76 | } 77 | ``` 78 | 79 | ### Timer 80 | ```cs 81 | CountDownRule cdr = new CountDownRule() { 82 | Delay = 3600, 83 | Enabled = true, 84 | PoweredOn = true, 85 | Name = "1h Timer" 86 | } 87 | await plug.AddCountDownRule(cdr); 88 | ``` 89 | 90 | ### Schedule 91 | ```cs 92 | Schedule schedule = new Schedule 93 | { 94 | Name = "TurnOffMondays10am", 95 | StartAction = 0, 96 | StartTime = new TimeSpan(10, 0, 0), 97 | StartTimeOption = TimeOption.Custom, 98 | Enabled = true, 99 | Weekdays = Weekdays.Monday, 100 | }; 101 | await plug.AddSchedule(schedule); 102 | ``` 103 | 104 | ### Remote Control 105 | 106 | If you still want to control your devices remotely (not from within the same network) there is the possibility to link each device independently to your kasa account. It then shows up in your app. 107 | ```cs 108 | smartdevice.ConfigureRemoteAccess("username", "password"); 109 | ``` 110 | To check if your device is linked to tplink cloud use `RemoteAccessEnabled` property. 111 | 112 | ## Disclaimer 113 | I can not guarantee the functionality of this library as I only tested a HS100 and a KL130 in a Xamarin.Android application yet. 114 | 115 | This library has no affiliation with TP-Link. 116 | TP-Link and all respective product names are copyright TP-Link Technologies Co, Ltd. and/or its subsidiaries and affiliates. 117 | -------------------------------------------------------------------------------- /TPLinkSmartDevices.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29503.13 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TPLinkSmartDevices", "tplink-smartdevices\TPLinkSmartDevices.csproj", "{2900B1BB-2ED5-455B-89B1-7668C6B77DF0}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {2900B1BB-2ED5-455B-89B1-7668C6B77DF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {2900B1BB-2ED5-455B-89B1-7668C6B77DF0}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {2900B1BB-2ED5-455B-89B1-7668C6B77DF0}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {2900B1BB-2ED5-455B-89B1-7668C6B77DF0}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {BAF6D4C7-56D0-4A2A-86EF-E1E1534BC246} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /docs/docs/about.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeBardian/tplink-smartdevices-netstandard/2566af2a3a184e9746934af5668c5ab9a8735b88/docs/docs/about.md -------------------------------------------------------------------------------- /docs/docs/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeBardian/tplink-smartdevices-netstandard/2566af2a3a184e9746934af5668c5ab9a8735b88/docs/docs/assets/icon.png -------------------------------------------------------------------------------- /docs/docs/docs/data/hsv.md: -------------------------------------------------------------------------------- 1 | # BulbHSV Class 2 | Namespace: TPLinkSmartDevices.Data

3 | represents a single color in the HSV color model to change a smart bulbs color 4 | 5 | ## Properties 6 | 7 | ### `Hue` 8 | : Angular dimension representing color, `0°/360°` red, `120°` green, `240°` blue 9 | ``` csharp 10 | public int Hue { get; set; } 11 | ``` 12 | 13 | ### `Saturation` 14 | : Resembles various tints of color. Accepts values from 0-100. 15 | ``` csharp 16 | public int Saturation { get; set; } 17 | ``` 18 | 19 | ### `Value` 20 | : Brightness of color (mixture of hue with varying amounts of black or white paint). Accepts values from 0-100. 21 | ``` csharp 22 | public int Value { get; set; } 23 | ``` -------------------------------------------------------------------------------- /docs/docs/docs/data/light-details.md: -------------------------------------------------------------------------------- 1 | # LightDetails Class 2 | Namespace: TPLinkSmartDevices.Data

3 | Encapsulates JSON data structure for specific hardware properties of smart bulbs. 4 | 5 | ## Properties 6 | 7 | ### `ColorRenderingIndex` 8 | : Measurement of how true the color of an object looks under the bulb's light. A good CRI for most indoor residential applications is 80 or above 9 | ``` csharp 10 | public int ColorRenderingIndex { get; set; } 11 | ``` 12 | 13 | ### `IncandescentEquivalent` 14 | : bulb equals a standard incandescent bulb with this watt value 15 | ``` csharp 16 | public int IncandescentEquivalent { get; set; } 17 | ``` 18 | 19 | ### `LampBeamAngle` 20 | : Angle at which the light is distributed or emitted 21 | ``` csharp 22 | public int LampBeamAngle { get; set; } 23 | ``` 24 | 25 | ### `MaxLumens` 26 | : maximum brightness of bulb in lumens 27 | ``` csharp 28 | public int MaxLumens { get; set; } 29 | ``` 30 | 31 | ### `MaxVoltage` 32 | : maximum operating voltage 33 | ``` csharp 34 | public int MaxVoltage { get; set; } 35 | ``` 36 | 37 | ### `MinVoltage` 38 | : minimum operating voltage 39 | ``` csharp 40 | public int MinVoltage { get; set; } 41 | ``` 42 | 43 | ### `Wattage` 44 | : energy usage of bulb in watt 45 | ``` csharp 46 | public int Wattage { get; set; } 47 | ``` -------------------------------------------------------------------------------- /docs/docs/docs/data/power.md: -------------------------------------------------------------------------------- 1 | # PowerData Class 2 | Namespace: TPLinkSmartDevices.Data

3 | Encapsulates JSON data structure for current energy use as metered by the HS110 Smart Energy Meter. 4 | 5 | ## Properties 6 | 7 | ### `Voltage` 8 | : Currently measured voltage in volts 9 | ``` csharp 10 | public double Voltage { get; private set; } 11 | ``` 12 | 13 | ### `Amperage` 14 | : Currently measured current in amperes 15 | ``` csharp 16 | public double Amperage { get; private set; } 17 | ``` 18 | 19 | ### `Power` 20 | : Currently measured power in watts 21 | ``` csharp 22 | public double Power { get; private set; } 23 | ``` 24 | 25 | ### `Total` 26 | : Total power consumption in kilowatthours 27 | ``` csharp 28 | public double Total { get; private set; } 29 | ``` -------------------------------------------------------------------------------- /docs/docs/docs/devices/bulb.md: -------------------------------------------------------------------------------- 1 | # TPLinkSmartBulb Class 2 | Namespace: TPLinkSmartDevices.Devices
3 | Inheritance: TPLinkSmartDevice -> TPLinkSmartBulb

4 | encloses bulb specific system information and bulb controls 5 | 6 | ## Properties 7 | 8 | ### `IsColor` 9 | : Returns whether bulb supports color changes 10 | ``` csharp 11 | public bool IsColor { get; private set; } 12 | ``` 13 | 14 | ### `IsDimmable` 15 | : Returns whether bulb supports dimming the brightness 16 | ``` csharp 17 | public bool IsDimmable { get; private set; } 18 | ``` 19 | 20 | ### `IsVariableColorTemperature` 21 | : Returns whether bulb supports changing of color temperature 22 | ``` csharp 23 | public bool IsVariableColorTemperature { get; private set; } 24 | ``` 25 | 26 | ### `Brightness` 27 | : Returns bulb brightness in percent 28 | ``` csharp 29 | public int Brightness { get; private set; } 30 | ``` 31 | 32 | ### `ColorTemperature` 33 | : Returns bulbs color temperature in kelvin 34 | ``` csharp 35 | public int ColorTemperature { get; private set; } 36 | ``` 37 | 38 | ### `LightDetails` 39 | : Contains further hardware specifications of this bulb, , see [`LightDetails`](/docs/data/light-details.md) reference 40 | ``` csharp 41 | public LightDetails LightDetails { get; private set; } 42 | ``` 43 | 44 | ### `HSV` 45 | : Returns bulb color in HSV scheme 46 | ``` csharp 47 | public BulbHSV HSV { get; private set; } 48 | ``` 49 | 50 | ### `PoweredOn` 51 | : Returns whether bulb is powered on 52 | ``` csharp 53 | public bool PoweredOn { get; private set; } 54 | ``` 55 | 56 | ### `PreferredLightStates` 57 | : Returns collection of the four light state preset configurations 58 | ``` csharp 59 | public List PreferredLightStates { get; } 60 | ``` 61 | 62 | ## Constructors 63 | 64 | ### `TPLinkSmartBulb(string, int)` 65 | : Creates a new object of this type, used for KL100/KL110/KL130 bulbs 66 | ``` csharp 67 | public TPLinkSmartBulb(string hostname, int port=9999) 68 | ``` 69 | 70 | __Parameters__ 71 | : * `#!csharp string hostname`: ip-address of of this bulb 72 | * `#!csharp int port`: bulb communicates on this port, defaults to `9999` 73 | 74 | ## Methods 75 | 76 | ### `Create(string, int)` {: #create } 77 | : Factory instantiation method. Returns a new instance of this type. 78 | ``` csharp 79 | public static async Task Create(string hostname, int port = 9999) 80 | ``` 81 | 82 | __Parameters__ 83 | : * `#!csharp string hostname`: ip-address of of this bulb 84 | * `#!csharp int port`: bulb communicates on this port, defaults to `9999` 85 | 86 | ### `Refresh()` 87 | : Refreshes all properties of this bulb (includes a call to [`TPLinkSmartDevice.Refresh(dynamic)`](device.md#refreshdynamic) for the common device information) 88 | ``` csharp 89 | public async Task Refresh() 90 | ``` 91 | 92 | ### `SetPoweredOn(bool)` 93 | : Change the power state of this bulb 94 | ``` csharp 95 | public async task SetPoweredOn(bool value) 96 | ``` 97 | 98 | __Parameters__ 99 | : * `#!csharp bool value`: `true` power on, `false` power off 100 | 101 | ### `SetBrightness(int, int)` 102 | : Change the bulbs brightness 103 | ``` csharp 104 | public void SetBrightness(int brightness, int transition_period = 0) 105 | ``` 106 | 107 | __Parameters__ 108 | : * `#!csharp int brightness`: brightness value in percent 109 | * `#!csharp int transition_period` (optional): time in milliseconds in which the bulb transitions from old to new brightness. Allowed values between `0` and `10000` 110 | 111 | __Exceptions__ 112 | : * `#!csharp NotSupportedException`: the bulb does not support dimming 113 | * `#!csharp ArgumentException`: `transition_period` only allows values between `0` and `10000` 114 | 115 | ### `SetColorTemp(int, int)` 116 | : Change the bulbs color temperature 117 | ``` csharp 118 | public void SetColorTemp(int colortemp, int transition_period = 0) 119 | ``` 120 | 121 | __Parameters__ 122 | : * `#!csharp int colortemp`: color temperature in kelvin, common values ranging between 2700K (soft light) to 6500K (bright daylight) 123 | * `#!csharp int transition_period` (optional): time in milliseconds in which the bulb transitions from old to new brightness. Allowed values between `0` and `10000` 124 | 125 | __Exceptions__ 126 | : * `#!csharp NotSupportedException`: the bulb does not support color temperature changes 127 | * `#!csharp ArgumentException`: `transition_period` only allows values between `0` and `10000` 128 | 129 | !!! note 130 | Color temperature values depend on device model, for instance KL120 supports 2500K-5000K and KL130 2700K-9000K! 131 | 132 | ### `SetHSV(BulbHSV, int)` {: #sethsv } 133 | : Change the bulbs color 134 | ``` csharp 135 | public void SetHSV(BulbHSV hsv, int transition_period = 0) 136 | ``` 137 | 138 | __Parameters__ 139 | : * `#!csharp BulbHSV hsv`: color in HSV color scheme, see [`BulbHSV`](/docs/data/hsv) reference 140 | * `#!csharp int transition_period` (optional): time in milliseconds in which the bulb transitions from old to new brightness. Allowed values between `0` and `10000` 141 | 142 | __Exceptions__ 143 | : * `#!csharp NotSupportedException`: the bulb does not support color changes 144 | * `#!csharp ArgumentException`: `transition_period` only allows values between `0` and `10000` 145 | 146 | __Example__ 147 | ``` csharp 148 | BulbHSV red = new BulbHSV { Hue = 0, Saturation = 100, Value = 100 }; // red HSV(0, 100, 100) 149 | 150 | smartBulb.SetHSV(red); 151 | ``` 152 | 153 | ### `ApplyPreset(int)` 154 | : Operate smart bulb on one of the four light state presets 155 | ``` csharp 156 | public void ApplyPreset(int presetIndex) 157 | ``` 158 | 159 | __Parameters__ 160 | : * `#!csharp int presetIndex`: index of the four presets, ranging from `0` to `3` 161 | 162 | __Exceptions__ 163 | : * `#!csharp ArgumentOutOfRangeException`: `presetIndex` only allows values between `0` and `3` 164 | -------------------------------------------------------------------------------- /docs/docs/docs/devices/device.md: -------------------------------------------------------------------------------- 1 | # TPLinkSmartDevice Class 2 | Namespace: TPLinkSmartDevices.Devices

3 | provides top-level functionalities which all smart devices use, including set up of remote access and several system information properties 4 | 5 | ## Properties 6 | 7 | ### `Alias` 8 | : Returns the user specified (or default) name of this device 9 | ``` csharp 10 | public string Alias { get; private set; } 11 | ``` 12 | 13 | ### `CloudServer` 14 | : Returns the name of the server this device communicates to for cloud commands 15 | ``` csharp 16 | public string CloudServer { get; private set; } 17 | ``` 18 | 19 | ### `DeviceId` 20 | : Returns the id of this device 21 | ``` csharp 22 | public string DeviceId { get; private set; } 23 | ``` 24 | 25 | ### `DevName` 26 | : Returns the name of this device 27 | ``` csharp 28 | public string DevName { get; private set; } 29 | ``` 30 | 31 | ### `FirmwareId` 32 | : Returns the firmware id of this device 33 | ``` csharp 34 | public string FirmwareId { get; private set; } 35 | ``` 36 | 37 | ### `HardwareId` 38 | : Returns the hardware id of this device 39 | ``` csharp 40 | public string HardwareId { get; private set; } 41 | ``` 42 | 43 | ### `HardwareVersion` 44 | : Returns the hardware version of this device 45 | ``` csharp 46 | public string HardwareVersion { get; private set; } 47 | ``` 48 | 49 | ### `Hostname` 50 | : Returns the ip-address of this device 51 | ``` csharp 52 | public string Hostname { get; private set; } 53 | ``` 54 | 55 | ### `LocationLatLong` 56 | : Returns the coordinates of the rough position the device is located at (location of network). `LocationLatLong[0]` is latitude, `LocationLatLong[1]` is longitude 57 | ``` csharp 58 | public double[] LocationLatLong { get; private set; } 59 | ``` 60 | 61 | !!! caution 62 | whether you find it questionable (I do!) or not, tp-link's devices collect data on position of your network. 63 | 64 | 65 | ### `MacAddress` 66 | : Returns the mac address of this device 67 | ``` csharp 68 | public string MacAddress { get; private set; } 69 | ``` 70 | 71 | ### `Model` 72 | : Returns the model and region code (EU,US,UK,JP, ...) of this device 73 | ``` csharp 74 | public string Model { get; private set; } 75 | ``` 76 | 77 | ### `OemId` 78 | : Returns the manufacturers id of this device 79 | ``` csharp 80 | public string OemId { get; private set; } 81 | ``` 82 | 83 | ### `Port` 84 | : Returns the port this device communicates on 85 | ``` csharp 86 | public int Port { get; private set; } 87 | ``` 88 | 89 | ### `RemoteAccessEnabled` 90 | : Returns whether this device is configured for remote access via Kasa app 91 | ``` csharp 92 | public bool RemoteAccessEnabled { get; private set; } 93 | ``` 94 | 95 | ### `RSSI` 96 | : Returns signal strength 97 | ``` csharp 98 | public int RSSI { get; private set; } 99 | ``` 100 | 101 | ### `Type` 102 | : 103 | ``` csharp 104 | public string Type { get; private set; } 105 | ``` 106 | 107 | ## Methods 108 | 109 | ### `ConfigureRemoteAccess(string, string)` 110 | : Binds account with the specified credentials to tp-link's cloud server 111 | ``` csharp 112 | public async Task ConfigureRemoteAccess(string username, string password) 113 | ``` 114 | 115 | __Parameters__ 116 | : * `#!csharp string username`: username (e-mail address) of kasa account 117 | * `#!csharp string password`: password of kasa account 118 | 119 | ### `UnbindRemoteAccess()` 120 | : Unbinds currently connected account from tp-link's cloud server 121 | ``` csharp 122 | public void UnbindRemoteAccess() 123 | ``` 124 | 125 | ### `GetCloudInfo()` 126 | : Refreshes cloud information and sets [`RemoteAccessEnabled`](#remoteaccessenabled) and [`CloudServer`](#cloudserver) properties accordingly 127 | ``` csharp 128 | public void GetCloudInfo() 129 | ``` 130 | 131 | ### `GetTime()` 132 | : Returns current internal time of this device 133 | ``` csharp 134 | public DateTime GetTime() 135 | ``` 136 | 137 | !!! danger "Needs Maintenance" 138 | This method needs maintenance. It is discouraged using it due to unexpected results or errors occurring 139 | 140 | ### `Refresh(dynamic)` 141 | : Refreshes all properties of this device (includes a call to [`GetCloudInfo()`](#getcloudinfo)) 142 | ``` csharp 143 | public async Task Refresh(dynamic sysInfo = null) 144 | ``` 145 | 146 | __Parameters__ 147 | : * `#!csharp dynamic sysInfo`: response of smart devices on system properties, defaults to `null` which results in a new request being made 148 | 149 | ### `SetAlias(string)` 150 | : Sets alias of this device 151 | ``` csharp 152 | public void SetAlias(string value) 153 | ``` 154 | 155 | __Parameters__ 156 | : * `#!csharp string value`: new alias to set 157 | 158 | 159 | -------------------------------------------------------------------------------- /docs/docs/docs/devices/dimmer.md: -------------------------------------------------------------------------------- 1 | # TPLinkSmartDimmmer Class 2 | Namespace: TPLinkSmartDevices.Devices
3 | Inheritance: TPLinkSmartDevice -> TPLinkSmartDimmer

4 | controls for wall switches with dimmer functionality 5 | 6 | ## Properties 7 | 8 | ### `Brightness` 9 | : Returns brightness (dimmer value) in percent 10 | ``` csharp 11 | public int Brightness { get; private set; } 12 | ``` 13 | 14 | ### `Options` 15 | : Returns an object of type [`DimmerOptions`]() with configuration properties 16 | ``` csharp 17 | public DimmerOptions Options { get; private set; } 18 | ``` 19 | 20 | ### `Presets` 21 | : Returns array of the four dimmer state preset configurations containing brightness values 22 | ``` csharp 23 | public int[] Presets { get; private set; } 24 | ``` 25 | 26 | ### `PoweredOn` 27 | : Returns whether switch is powered on 28 | ``` csharp 29 | public bool PoweredOn { get; private set; } 30 | ``` 31 | 32 | ## Constructors 33 | 34 | ### `TPLinkSmartPlug(string, int, DimmerOptions)` 35 | : Creates a new object of this type, used for HS220 wall switch 36 | ``` csharp 37 | public TPLinkSmartPlug(string hostname, int port=9999, DimmerOptions opts = null) 38 | ``` 39 | 40 | __Parameters__ 41 | : * `#!csharp string hostname`: ip-address of this device 42 | * `#!csharp int port`: device communicates on this port, defaults to `9999` 43 | * `#!csharp DimmerOptions opts`: configuration properties` 44 | 45 | ## Methods 46 | 47 | ### `Create(string, int, DimmerOptions)` {: #create } 48 | : Factory instantiation method. Returns a new instance of this type. 49 | ``` csharp 50 | public static async Task Create(string hostname, int port = 9999, DimmerOptions opts = null) 51 | ``` 52 | 53 | __Parameters__ 54 | : * `#!csharp string hostname`: ip-address of this device 55 | * `#!csharp int port`: device communicates on this port, defaults to `9999` 56 | * `#!csharp DimmerOptions opts`: configuration properties` 57 | 58 | ### `Refresh()` 59 | : Refreshes all properties of this device (includes a call to [`TPLinkSmartDevice.Refresh(dynamic)`](device.md#refreshdynamic) for the common device information) 60 | ``` csharp 61 | public async Task Refresh() 62 | ``` 63 | 64 | ### `SetPoweredOn(bool)` 65 | : Change the power state 66 | ``` csharp 67 | public void SetPoweredOn(bool value) 68 | ``` 69 | 70 | __Parameters__ 71 | : * `#!csharp bool value`: `true` power on, `false` power off 72 | 73 | ### `TransitionBrightness(int, DimmerMode, int)` 74 | : Transition to a specified brightness level 75 | ``` csharp 76 | public async Task TransitionBrightness(int brightness, DimmerMode? mode = null, int? duration = null) 77 | ``` 78 | 79 | __Parameters__ 80 | : * `#!csharp int brightness`: dimmer brightness value in percent 81 | * `#!csharp DimmerMode mode` (optional): [`DimmerMode`]() to use during this transition, if left empty uses default option from [`Options.Mode`](#options) 82 | * `#!csharp int duration` (optional): time in milliseconds in which the bulb transitions from old to new brightness 83 | 84 | __Exceptions__ 85 | : * `#!csharp ArgumentException`: `brightness` should be between `0` and `100` 86 | 87 | ### `SetBrightness(int)` 88 | : Instantly change to a specified brightness level 89 | ``` csharp 90 | public async Task SetBrightness(int brightness) 91 | ``` 92 | 93 | __Parameters__ 94 | : * `#!csharp int brightness`: dimmer brightness value in percent 95 | 96 | __Exceptions__ 97 | : * `#!csharp ArgumentException`: `brightness` should be between `0` and `100` 98 | 99 | ### `SetDoubleClickAction(DimmerMode, int)` 100 | : Configures change mode on double click of switch 101 | ``` csharp 102 | public async Task SetDoubleClickAction(DimmerMode mode, int index=0) 103 | ``` 104 | 105 | __Parameters__ 106 | : * `#!csharp DimmerMode mode`: [`DimmerMode`]() to use on double clicking the switch 107 | * `#!csharp int index` (optional): zero-based preset index, use in combination with `DimmerMode.Preset` to execute preset on double click 108 | 109 | __Exceptions__ 110 | : * `#!csharp ArgumentException`: `index` should be between `0` and `3` 111 | 112 | ### `SetLongPressAction(DimmerMode, int)` 113 | : Configures change mode on long press of switch 114 | ``` csharp 115 | public async Task SetLongPressAction(DimmerMode mode, int index=0) 116 | ``` 117 | 118 | __Parameters__ 119 | : * `#!csharp DimmerMode mode`: [`DimmerMode`]() to use on long press of switch 120 | * `#!csharp int index` (optional): zero-based preset index, use in combination with `DimmerMode.Preset` to execute preset on long press 121 | 122 | __Exceptions__ 123 | : * `#!csharp ArgumentException`: `index` should be between `0` and `3` 124 | 125 | ### `SetFadeOnTime(int)` 126 | : Configures speed of fade on transition 127 | ``` csharp 128 | public async Task SetFadeOnTime(int fadeOnTime) 129 | ``` 130 | 131 | __Parameters__ 132 | : * `#!csharp int fadeOnTime`: transition time used on next uses of switch when turning on 133 | 134 | __Exceptions__ 135 | : * `#!csharp ArgumentException`: `fadeOnTime` should be a positive number 136 | 137 | ### `SetFadeOffTime(int)` 138 | : Configures speed of fade on transition 139 | ``` csharp 140 | public async Task SetFadeOffTime(int fadeOffTime) 141 | ``` 142 | 143 | __Parameters__ 144 | : * `#!csharp int fadeOffTime`: transition time used on next uses of switch when turning off 145 | 146 | __Exceptions__ 147 | : * `#!csharp ArgumentException`: `fadeOffTime` should be a positive number 148 | -------------------------------------------------------------------------------- /docs/docs/docs/devices/multi-plug.md: -------------------------------------------------------------------------------- 1 | # TPLinkSmartMultiPlug Class 2 | Namespace: TPLinkSmartDevices.Devices
3 | Inheritance: TPLinkSmartDevice -> TPLinkSmartMultiPlug

4 | encloses plug specific system information and controls for plugs with multiple outlets 5 | 6 | ## Properties 7 | 8 | ### `AllOutletsPowered` 9 | : Returns whether all the plugs outlet relais are powered on 10 | ``` csharp 11 | public bool AllOutletsPowered { get; private set; } 12 | ``` 13 | 14 | ### `Features` 15 | : Returns the feature (capability) abbreviations for this plug 16 | ``` csharp 17 | public string[] Features { get; private set; } 18 | ``` 19 | 20 | ### `LedOn` 21 | : If status led on smart plug is on 22 | ``` csharp 23 | public bool LedOn { get; private set; } 24 | ``` 25 | 26 | ### `OutletCount` 27 | : Returns number of outlets on this plug 28 | ``` csharp 29 | public int OutletCount { get; private set; } 30 | ``` 31 | 32 | ### `Outlets` 33 | : Returns array of Outlets, containing id's, names and power states of each outlet 34 | ``` csharp 35 | public Outlet[] Outlets { get; private set; } 36 | ``` 37 | 38 | ## Constructors 39 | 40 | ### `TPLinkSmartMultiPlug(string, int)` 41 | : Creates a new object of this type, used for HS300/HS107 plug 42 | ``` csharp 43 | public TPLinkSmartPlug(string hostname, int port=9999) 44 | ``` 45 | 46 | __Parameters__ 47 | : * `#!csharp string hostname`: ip-address of of this plug 48 | * `#!csharp int port`: plug communicates on this port, defaults to `9999` 49 | 50 | ## Methods 51 | 52 | ### `Refresh()` 53 | : Refreshes all properties of this plug (includes a call to [`TPLinkSmartDevice.Refresh(dynamic)`](device.md#refreshdynamic) for the common device information) 54 | ``` csharp 55 | public async Task Refresh() 56 | ``` 57 | 58 | ### `SetOutletPowered(bool, int)` 59 | : Change the plugs outlet relay state 60 | ``` csharp 61 | public void SetOutletPowered(bool value, int outledId = -1) 62 | ``` 63 | 64 | __Parameters__ 65 | : * `#!csharp bool value`: `true` power on, `false` power off 66 | * `#!csharp int outledId`: id of outlet to turn on/off (zero-based index of all outlets) 67 | 68 | __Exceptions__ 69 | : * `#!csharp ArgumentException`: plug does not have a outlet with specified `outledId` 70 | 71 | ### `SetLedOn(bool)` 72 | : Change the plugs LED state; branded as night mode by tp-link :) 73 | ``` csharp 74 | public void SetLedOn(bool value) 75 | ``` 76 | 77 | __Parameters__ 78 | : * `#!csharp bool value`: `true` LED on (day mode), `false` LED off (night mode) -------------------------------------------------------------------------------- /docs/docs/docs/devices/plug.md: -------------------------------------------------------------------------------- 1 | # TPLinkSmartPlug Class 2 | Namespace: TPLinkSmartDevices.Devices
3 | Inheritance: TPLinkSmartDevice -> TPLinkSmartPlug

4 | encloses plug specific system information and plug controls 5 | 6 | ## Properties 7 | 8 | ### `Features` 9 | : Returns the feature (capability) abbreviations for this plug 10 | ``` csharp 11 | public string[] Features { get; private set; } 12 | ``` 13 | 14 | ### `LedOn` 15 | : If status led on smart plug is on 16 | ``` csharp 17 | public bool LedOn { get; private set; } 18 | ``` 19 | 20 | ### `OutletPowered` 21 | : Returns whether the plugs outlet relay is powered on 22 | ``` csharp 23 | public bool OutletPowered { get; private set; } 24 | ``` 25 | 26 | ### `PoweredOnSince` 27 | : Returns `#!csharp DateTime` the relay was powered on 28 | ``` csharp 29 | public DateTime PoweredOnSince { get; private set; } 30 | ``` 31 | 32 | ## Constructors 33 | 34 | ### `TPLinkSmartPlug(string, int)` 35 | : Creates a new object of this type, used for HS100/HS105 plug 36 | ``` csharp 37 | public TPLinkSmartPlug(string hostname, int port=9999) 38 | ``` 39 | 40 | __Parameters__ 41 | : * `#!csharp string hostname`: ip-address of of this plug 42 | * `#!csharp int port`: plug communicates on this port, defaults to `9999` 43 | 44 | ## Methods 45 | 46 | ### `Create(string, int)` {: #create } 47 | : Factory instantiation method. Returns a new instance of this type. 48 | ``` csharp 49 | public static async Task Create(string hostname, int port = 9999) 50 | ``` 51 | 52 | __Parameters__ 53 | : * `#!csharp string hostname`: ip-address of of this plug 54 | * `#!csharp int port`: plug communicates on this port, defaults to `9999` 55 | 56 | ### `Refresh()` 57 | : Refreshes all properties of this plug (includes a call to [`TPLinkSmartDevice.Refresh(dynamic)`](device.md#refreshdynamic) for the common device information) 58 | ``` csharp 59 | public async Task Refresh() 60 | ``` 61 | 62 | ### `SetPoweredOn(bool)` {: #power } 63 | : Change the plugs outlet relay state 64 | ``` csharp 65 | public async Task SetPoweredOn(bool value) 66 | ``` 67 | 68 | __Parameters__ 69 | : * `#!csharp bool value`: `true` power on, `false` power off 70 | 71 | ### `SetLedOn(bool)` 72 | : Change the plugs LED state; branded as night mode by tp-link :) 73 | ``` csharp 74 | public void SetLedOn(bool value) 75 | ``` 76 | 77 | __Parameters__ 78 | : * `#!csharp bool value`: `true` LED on (day mode), `false` LED off (night mode) -------------------------------------------------------------------------------- /docs/docs/docs/devices/smartmeter-plug.md: -------------------------------------------------------------------------------- 1 | # TPLinkSmartMeterPlug Class 2 | Namespace: TPLinkSmartDevices.Devices
3 | Inheritance: TPLinkSmartPlug -> TPLinkSmartMeterPlug

4 | provides data on power consumption of comsumers connected to a HS110 plug 5 | 6 | ## Properties 7 | 8 | ### `CurrentPowerUsage` 9 | : Returns a [`PowerData`](/docs/data/power) object including power usage data from the latest call to the construtor or [`.Refresh()`](#refresh) 10 | ``` csharp 11 | public PowerData CurrentPowerUsage { get; private set; } 12 | ``` 13 | 14 | ### `IGain` 15 | : Returns ratio of output current to input current. 16 | ``` csharp 17 | public uint IGain { get; private set; } 18 | ``` 19 | 20 | ### `VGain` 21 | : Returns ratio of output voltage to input voltage. 22 | ``` csharp 23 | public uint VGain { get; private set; } 24 | ``` 25 | 26 | ## Constructors 27 | 28 | ### `TPLinkSmartMeterPlug(string)` 29 | : Creates a new object of this type, used for HS110 plug 30 | ``` csharp 31 | public TPLinkSmartMeterPlug(string hostname) 32 | ``` 33 | 34 | __Parameters__ 35 | : * `#!csharp string hostname`: ip-address of of this plug 36 | 37 | ## Methods 38 | 39 | ### `Create(string, int)` {: #create } 40 | : Factory instantiation method. Returns a new instance of this type. 41 | ``` csharp 42 | public static async Task Create(string hostname, int port = 9999) 43 | ``` 44 | 45 | __Parameters__ 46 | : * `#!csharp string hostname`: ip-address of of this plug 47 | * `#!csharp int port`: plug communicates on this port, defaults to `9999` 48 | 49 | ### `Refresh()` 50 | : Updates current power usage, gain data and all other properties of this plug (includes a call to [`TPLinkSmartPlug.Refresh()`](plug.md#refresh) for the common device information) 51 | ``` csharp 52 | public async Task Refresh() 53 | ``` 54 | 55 | ### `EraseStats()` 56 | : Erases all collected e-meter statistics of this plug 57 | ``` csharp 58 | public void EraseStats() 59 | ``` 60 | 61 | 62 | ### `GetMonthStats(DateTime, float)` 63 | : Queries collected usage statistics from a specific month. Returns a `#!csharp Dictionary` of each day in a month and energy consumption of that day in kWh) 64 | ``` csharp 65 | public async Task> GetMonthStats(int month, int year) 66 | ``` 67 | 68 | __Parameters__ 69 | : * `#!csharp int month`: month of year, ranging from `1`(January) to `12`(December) 70 | * `#!csharp int year`: 71 | 72 | ### `GetYearStats(int, float)` 73 | : Queries collected usage statistics for a whole year. Returns a `#!csharp Dictionary` of each month and energy consumption of that month in kWh) 74 | ``` csharp 75 | public async Task> GetYearStats(int year) 76 | ``` 77 | 78 | __Parameters__ 79 | : * `#!csharp int year`: -------------------------------------------------------------------------------- /docs/docs/docs/discovery.md: -------------------------------------------------------------------------------- 1 | # TPLinkDiscovery Class 2 | Namespace: TPLinkSmartDevices

3 | handles discovery of new smart devices and connection of factory new devices to a network 4 | 5 | ## Properties 6 | 7 | ### `DiscoveredDevices` 8 | : Returns a list of [`TPLinkSmartDevice`](devices/device.md)'s from the latest call of [`.Discover()`](discovery.md#discover). This property is read-only. 9 | ``` csharp 10 | public List DiscoveredDevices { get; private set; } 11 | ``` 12 | 13 | ## Methods 14 | 15 | ### `Discover(int, int, string)` {: #discover } 16 | : Discovers smart devices within the network of the host via UDP broadcast. Returns a list of [`TPLinkSmartDevice`](devices/device.md)'s. 17 | ``` csharp 18 | public async Task> Discover(int port=9999, int timeout=5000, string target="255.255.255.255") 19 | ``` 20 | 21 | __Parameters__ 22 | : * `#!csharp int port`: Listen to broadcast responses on this port, defaults to `9999` 23 | * `#!csharp int timeout`: Timespan after which the discovery finishes, defaults to `5000`(5 seconds) 24 | * `#!csharp string target`: ip address of discovery broadcast, defaults to `255.255.255.255` 25 | 26 | !!! tip 27 | The discovery of devices within a network fails under certain circumstances. Some routers seem to block udp packets to the broadcast address (255.255.255.255), which is used to send out a discovery request. 28 | In case of using different subnet's, what seems to resolve the issue is broadcasting to the subnet's local broadcast IP (such as 192.168.0.255, if IP is 192.168.0.X with a subnet mask of 255.255.255.0) 29 | 30 | ### `Associate(string, string, int)` 31 | : Makes smart device connect to specified network credentials 32 | ``` csharp 33 | public async Task Associate(string ssid, string password, int type = 3) 34 | ``` 35 | 36 | __Parameters__ 37 | : * `#!csharp string ssid`: _Service Set Identifier_ (name) of network to connect to 38 | * `#!csharp string password`: password of network to connect to 39 | * `#!csharp int type`: network protection level, defaults to `3` indicating WPA2 40 | 41 | !!! caution 42 | Host who runs the application needs to be connected to the open configuration network! (TP-Link_Smart Plug_XXXX or similar) 43 | 44 | ## Events 45 | 46 | ### `DeviceFound` 47 | : Triggers when smart device is found during discovery process, granting access to all system properties of that device via the event args 48 | ``` csharp 49 | public event EventHandler DeviceFound; 50 | ``` 51 | 52 | __EventArgs__ 53 | : * `#!csharp DeviceFoundEventArgs e` 54 | 55 | __Example__ 56 | : 57 | ``` csharp 58 | new TPLinkDiscovery().DeviceFound += (s, e) { 59 | ... 60 | Console.WriteLine($"Device found: {e.Device.Alias}"); 61 | ... 62 | }; 63 | ``` -------------------------------------------------------------------------------- /docs/docs/docs/index.md: -------------------------------------------------------------------------------- 1 | # Full API Reference 2 | 3 | ## Classes 4 | 5 | | TPLinkSmartDevices | Description | 6 | | :---------------------------------| :----------------------------------- | 7 | | [`TPLinkDiscovery`](discovery.md) | handles discovery of new smart devices and connection of factory new devices to a network | 8 | 9 | | TPLinkSmartDevices.Devices | Description | 10 | | :----------------------------------------- | :----------------------------------- | 11 | | [`TPLinkSmartDevice`](devices/device.md) | provides top-level functionalities which all smart devices use, including set up of remote access and several system information properties| 12 | | [`TPLinkSmartPlug`](devices/plug.md) | encloses plug specific system information and plug controls | 13 | | [`TPLinkSmartMeterPlug`](devices/smartmeter-plug.md) | provides data on power consumption of comsumers connected to a HS110 plug | 14 | | [`TPLinkSmartBulb`](devices/bulb.md) | encloses bulb specific system information and bulb controls | 15 | | [`TPLinkSmartMultiPlug`](devices/multi-plug.md) | encloses plug specific system information and controls for plugs with multiple outlets | 16 | | [`TPLinkSmartDimmer`](devices/dimmer.md) | controls for wall switches with dimmer functionality | 17 | 18 | | TPLinkSmartDevices.Data | Description | 19 | | :---------------------------- | :----------------------------------- | 20 | | [`BulbHSV`](data/hsv.md) | represents a single color in the HSV color model to change a smart bulbs color | 21 | | [`PowerData`](data/power.md) | Encapsulates JSON data structure for current energy use as metered by the HS110 Smart Energy Meter | 22 | | [`LightDetails`](data/light-details.md) | Encapsulates JSON data structure for specific hardware properties of smart bulbs | -------------------------------------------------------------------------------- /docs/docs/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ## Installation 4 | 5 | Use NuGet package manager to add a reference to this project 6 | 7 | === ".NET CLI" 8 | ``` 9 | > dotnet add package tplink-smartdevices --version 2.0.0 10 | ``` 11 | === "PackageReference" 12 | ``` html 13 | 14 | ``` 15 | === "Package Manager" 16 | ``` 17 | Install-Package tplink-smartdevices -Version 2.0.0 18 | ``` 19 | 20 | 21 | !!! note ".NET Standard" 22 | Be aware that this library targets .net standard, which can not be implemented from all of .net platform versions. To see whether the platform you intend to run on is supported take a look [here](https://github.com/dotnet/standard/blob/master/docs/versions.md). 23 | 24 | ## Supported Devices 25 | 26 | | Class | Supported Devices | Not tested, maybe working | 27 | | ----------------------- | ----------------- |---------------------------------- | 28 | | `TPLinkSmartPlug` | HS100 | HS105 | 29 | | `TPLinkSmartMeterPlug` | HS110 | | 30 | | `TPLinkSmartBulb` | KL100/KL110/KL130 | KL50/KL60/LB100/LB110/LB120/LB130 | 31 | | `TPLinkSmartMultiPlug` | HS300/HS107 | KP200/KP303/KP400 | 32 | | `TPLinkSmartDimmer` | HS220 | | 33 | 34 | ## Usage 35 | 36 | ### First Use 37 | 38 | If your devices are already connected to your Wi-Fi network (e.g through TP-Link provided mobile app Kasa) this step can be skipped. Otherwise you can use the following script to associate your smart devices with your home network: 39 | 40 | ``` csharp 41 | await new TPLinkDiscovery().Associate("ssid", "password"); 42 | ``` 43 | 44 | Full reference for [`TPLinkDiscovery().Associate(string, string)`](docs/discovery.md#associatestring-string-int) 45 | 46 | !!! caution 47 | The device running the above script needs to be connected to the network which the tplink smart devices provide. They should be called "TP-Link_Smart Plug_XXXX" or similar. If you have a brand new plug/bulb this network should automatically appear. Otherwise, hold down the reset button on a plug for about 10 seconds, until its light blinks amber rapidly. For a bulb flip the switch on and off 5 times. Not too quickly though! (About 1 sec per flip). 48 | 49 | ### Discovery 50 | 51 | Smart devices which are already connected to the same network as the host devices (PC, tablet, phone, ...) can be discovered to establish further communcation such as turning the device on/off. The discovery runs in an async `Task>`. There is the possibility to register an event handler which triggers on each discovered device. If the ip-address of smart devices are known and not changing, an object of their associated [classes](#supported-devices) can be created manually without the need for discovery. 52 | 53 | === "Basic" 54 | ``` csharp 55 | var discoveredDevices = await new TPLinkDiscovery().Discover(); 56 | ``` 57 | Full reference for [`TPLinkDiscovery.Discover()`](docs/discovery.md#discover) 58 | === "With event" 59 | ``` csharp 60 | TPLinkDiscovery discovery = new TPLinkDiscovery(); 61 | discovery.DeviceFound += delegate { 62 | ... 63 | Console.WriteLine($"Device found: {e.Device.Alias}"); 64 | ... 65 | }; 66 | var discoveredDevices = await discovery.Discover(); 67 | ``` 68 | Full reference for [`TPLinkDiscovery.DeviceFound`](docs/discovery.md#devicefound) 69 | === "Manual instantiation" 70 | ``` csharp 71 | //with constructor (blocking!) 72 | var smartPlug = new TPLinkSmartPlug("100.10.4.1"); 73 | //or with async factory method 74 | var smartBulb = await TPLinkSmartPlug.Create("100.10.4.1"); 75 | ``` 76 | Full reference for [`TPLinkSmartPlug`](docs/devices/plug.md) and [`TPLinkSmartBulb`](docs/devices/bulb.md) 77 | 78 | ### Basic Usage Examples 79 | 80 | Following script is a basic example which describes the use-case of turning on all smart plugs in your current network: 81 | 82 | ``` csharp 83 | var discoveredDevices = await new TPLinkDiscovery().Discover(); 84 | 85 | foreach (var item in discoveredDevices) 86 | { 87 | if (item is TPLinkSmartPlug plug) 88 | { 89 | await plug.SetPoweredOn(true); 90 | } 91 | } 92 | ``` 93 | Full reference for [`TPLinkSmartPlug.SetPoweredOn(bool)`](docs/devices/plug.md#power) 94 | 95 | Changing color of a single smart bulb (LB130, KL130): 96 | 97 | ``` csharp 98 | var smartBulb = await TPLinkSmartBulb.Create("100.10.4.1"); 99 | 100 | BulbHSV red = new BulbHSV { Hue = 0, Saturation = 100, Value = 100 }; // red HSV(0, 100, 100) 101 | BulbHSV yellow = new BulbHSV { Hue = 60, Saturation = 100, Value = 100 }; // yellow HSV(60, 100, 100) 102 | 103 | //apply color (instant) 104 | smartBulb.SetHSV(red); 105 | //apply color with transition time 106 | smartBulb.SetHSV(yellow, 1000); 107 | ``` 108 | Full reference for [`TPLinkSmartBulb.SetHSV(BulbHSV, int)`](docs/devices/bulb.md#sethsv) 109 | 110 | ### Remote Control 111 | 112 | If you want to control your devices remotely (not from within the same network) there is the possibility to link each device independently to your kasa account. It then shows up in your Kasa app and can be controlled over the internet from wherever it's needed. 113 | 114 | ``` csharp 115 | smartDevice.ConfigureRemoteAccess("username", "password"); 116 | ``` 117 | Full reference for [`TPLinkSmartDevice.ConfigureRemoteAccess(string, string)`](docs/devices/device.md#configureremoteaccessstring-string) 118 | 119 | ### Timer 120 | 121 | By setting up a Countdown Rule it is possible to have a device execute a specific action after a certain time runs out. This can for example be used to turn off all devices after half an hour: 122 | 123 | ``` csharp 124 | List cdDevices = discoveredDevices.OfType().ToList(); 125 | cdDevices.ForEach(d => 126 | d.AddCountDownRule( 127 | new CountDownRule() { 128 | Delay = 1800, 129 | Enabled = true, 130 | PoweredOn = false, 131 | Name = "MyTimer" 132 | } 133 | ) 134 | ); 135 | ``` 136 | Full reference for [`CountDownRules`](timer.md) 137 | 138 | ### Schedule 139 | Schedule your smart devices to automatically switch on or off if you are home or away, on sunrise or sunset or whenever you feel like. Example of turning light bulb on each workday at 07:00 in the morning. 140 | ``` csharp 141 | Schedule schedule = new Schedule 142 | { 143 | Name = "MySchedule", 144 | StartAction = 1, 145 | StartTime = new TimeSpan(7, 0, 0), 146 | StartTimeOption = TimeOption.Custom, 147 | Enabled = true, 148 | Weekdays = Weekdays.WorkDays 149 | }; 150 | await smartBulb.AddSchedule(schedule); 151 | ``` 152 | Full reference for [`Schedule`](schedule.md) -------------------------------------------------------------------------------- /docs/docs/index.md: -------------------------------------------------------------------------------- 1 | # Welcome to tplink-smartdevices Documentation 2 | 3 | __tplink-smartdevices__ is a .NET standard 2.0 library for discovering and operating TP-Link Smart Devices. It allows a developer to discover and operate TP-Link Smart Devices from multiple .NET implementations such as .NET Core, Xamarin, .NET Framework and more.
4 | 5 | ### Ready to dive in ? 6 | 7 | [Get Started](getting-started.md){: .md-button .md-button--primary } 8 | [Full Documentation](docs/index.md){: .md-button } 9 |
10 | 11 | * [Common Issues](https://www.github.com/CodeBardian/tplink-smartdevices-netstandard) 12 | * [Changelog](https://github.com/CodeBardian/tplink-smartdevices-netstandard/blob/master/CHANGELOG.md) 13 | 14 | ## Supported Devices 15 | 16 | | Class | Supported Devices | Not tested, maybe working | 17 | | ----------------------- | ----------------- |---------------------------------- | 18 | | `TPLinkSmartPlug` | HS100 | HS105, HS200 | 19 | | `TPLinkSmartMeterPlug` | HS110 | | 20 | | `TPLinkSmartBulb` | KL100/KL110/KL130 | KL50/KL60/LB100/LB110/LB120/LB130 | 21 | | `TPLinkSmartMultiPlug` | HS300/HS107 | KP200/KP303/KP400 | 22 | | `TPLinkSmartDimmer` | HS220 | | 23 | -------------------------------------------------------------------------------- /docs/docs/schedule.md: -------------------------------------------------------------------------------- 1 | 2 | All devices implementing `ISchedule` can perform certain actions repeatedly on a specific time. Use `Schedule` to specify the options. Schedules are executed when the time of day equals `StartTime` as long as 3 | the schedule is `Enabled`. All created schedules can be accessed via the `Schedules` property. 4 | 5 | ``` csharp 6 | Schedule schedule = new Schedule 7 | { 8 | Name = "Test1", 9 | StartAction = 1, 10 | StartTime = new TimeSpan(13, 1, 0), 11 | StartTimeOption = TimeOption.Custom, 12 | Enabled = true, 13 | Weekdays = Weekdays.WeekendDays, 14 | }; 15 | await device.AddSchedule(schedule); 16 | ``` 17 | 18 | #### Options 19 | 20 | | Property | Type | Description | 21 | | ----------------------- | ----------------- |---------------------------------- | 22 | | `Name` | string | custom name of schedule, shows in kasa app | 23 | | `Enabled` | bool | if the schedule is currently active or not | 24 | | `StartAction` | int | whether to turn device on or off at start of rule. 0 = turn off, 1 = turn on | 25 | | `StartTimeOption` | TimeOption | `TimeOption.Sunset` and `TimeOption.Sunrise` trigger the action at, well, sunset or sunrise. Use `TimeOption.Custom` in conjunction with `StartTime` to set your own timing| 26 | | `StartTime` | TimeSpan | time on which the action triggers when using `StartTimeOption = TimeOption.Custom` e.g. 13:05 would be `TimeSpan(13, 5, 0)` or you can specify in minutes after midnight with `TimeSpan.FromMinutes(785)` | 27 | | `Weekdays` | Weekdays | flag of days on which the schedule is executed. Combine multiple days with bitwise or - operator `Weekdays = Weekdays.Monday | Weekdays.Friday` or use preset combinations like `Weekdays = Weekdays.WeekendDays`| 28 | 29 | some more options are available, they are not well tested as of version 2.0.0 30 | 31 | #### Methods 32 | 33 | ``` csharp 34 | Task ICountDown.RetrieveSchedules(); 35 | ``` 36 | queries the device for current schedules and updates `Schedules` respectively. 37 | 38 | --- 39 | ``` csharp 40 | Task ICountDown.AddSchedule(Schedule); 41 | ``` 42 | adds a new schedule 43 | 44 | --- 45 | ``` csharp 46 | Task ICountDown.EditSchedule(Schedule); 47 | ``` 48 | update an existing schedule. Example: 49 | ``` csharp 50 | device.Schedule[0].Weekdays |= Weekdays.Thursday; 51 | await device.EditSchedule(Schedule[0]); 52 | ``` 53 | 54 | --- 55 | ``` csharp 56 | Task ICountDown.DeleteSchedule(Schedule); 57 | ``` 58 | deletes an existing schedule. Example: 59 | ``` csharp 60 | await device.DeleteSchedule(Schedules[0]); 61 | ``` 62 | 63 | --- 64 | ``` csharp 65 | Task ICountDown.Schedules(); 66 | ``` 67 | deletes all existing schedules. -------------------------------------------------------------------------------- /docs/docs/timer.md: -------------------------------------------------------------------------------- 1 | 2 | All Devices implementing `ICountDown` can perform certain actions after a timer runs out. Use `CountDownRule` to specify the timer options. All timers only run once, for repeated actions create a [`Schedule`](timer.md). 3 | Currently active timers can be accessed via the `CountDownRules` property. 4 | 5 | ``` csharp 6 | var cdr = new CountDownRule() { 7 | Delay = 1800, 8 | Enabled = true, 9 | PoweredOn = false, 10 | Name = "MyTimer" 11 | } 12 | await device.AddCountDownRule(cdr); 13 | ``` 14 | 15 | #### Options 16 | 17 | | Property | Type | Description | 18 | | ----------------------- | ----------------- |---------------------------------- | 19 | | `Name` | string | custom name of timer, shows in kasa app | 20 | | `Enabled` | bool | if the rule is currently active or not | 21 | | `PoweredOn` | bool | if the device should be powered on or off after the timer runs out | 22 | | `Delay` | int | delay in seconds after which the action triggers | 23 | 24 | #### Methods 25 | 26 | ``` csharp 27 | Task ICountDown.RetrieveCountDownRules(); 28 | ``` 29 | queries the device for current timers and updates `CountDownRules` respectively. 30 | 31 | --- 32 | ``` csharp 33 | Task ICountDown.AddCountDownRule(CountDownRule); 34 | ``` 35 | adds a new rule 36 | 37 | --- 38 | ``` csharp 39 | Task ICountDown.EditCountDownRule(CountDownRule); 40 | ``` 41 | update an existing rule. Example: 42 | ``` csharp 43 | device.CountDownRules[0].Delay = 36000; 44 | await device.EditCountDownRule(CountDownRules[0]); 45 | ``` 46 | 47 | --- 48 | ``` csharp 49 | Task ICountDown.DeleteCountDownRule(CountDownRule); 50 | ``` 51 | deletes an existing rule. Example: 52 | ``` csharp 53 | await device.DeleteCountDownRule(CountDownRules[0]); 54 | ``` 55 | 56 | --- 57 | ``` csharp 58 | Task ICountDown.DeleteAllCountDownRules(); 59 | ``` 60 | deletes all existing rules. -------------------------------------------------------------------------------- /docs/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: tplink-smartdevices-docs 2 | nav: 3 | - Home: 'index.md' 4 | - 'Getting Started': 'getting-started.md' 5 | - Timer: 'timer.md' 6 | - Schedule: 'schedule.md' 7 | - Docs: 8 | - 'TPLinkDiscovery': 'docs/discovery.md' 9 | - Devices: 10 | - 'TPLinkSmartDevice': 'docs/devices/device.md' 11 | - 'TPLinkSmartPlug': 'docs/devices/plug.md' 12 | - 'TPLinkSmartMeterPlug': 'docs/devices/smartmeter-plug.md' 13 | - 'TPLinkSmartBulb': 'docs/devices/bulb.md' 14 | - 'TPLinkSmartMultiPlug': 'docs/devices/multi-plug.md' 15 | - 'TPLinkSmartDimmer': 'docs/devices/dimmer.md' 16 | - Data: 17 | - 'BulbHSV': 'docs/data/hsv.md' 18 | - 'PowerData': 'docs/data/power.md' 19 | - 'LightDetails': 'docs/data/light-details.md' 20 | theme: 21 | name: material 22 | favicon: assets/icon.png 23 | extra: 24 | social: 25 | - icon: fontawesome/brands/github 26 | link: https://github.com/CodeBardian 27 | repo_url: https://www.github.com/CodeBardian/tplink-smartdevices-netstandard 28 | repo_name: CodeBardian/tplink-smartdevices-netstandard 29 | markdown_extensions: 30 | - admonition 31 | - attr_list 32 | - def_list 33 | - pymdownx.tabbed 34 | - pymdownx.superfences 35 | - pymdownx.inlinehilite 36 | - pymdownx.highlight 37 | - pymdownx.snippets 38 | google_analytics: 39 | - UA-145854471-2 40 | - auto -------------------------------------------------------------------------------- /docs/site/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeBardian/tplink-smartdevices-netstandard/2566af2a3a184e9746934af5668c5ab9a8735b88/docs/site/assets/icon.png -------------------------------------------------------------------------------- /docs/site/assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeBardian/tplink-smartdevices-netstandard/2566af2a3a184e9746934af5668c5ab9a8735b88/docs/site/assets/images/favicon.png -------------------------------------------------------------------------------- /docs/site/assets/javascripts/lunr/min/lunr.da.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Danish` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.da=function(){this.pipeline.reset(),this.pipeline.add(e.da.trimmer,e.da.stopWordFilter,e.da.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.da.stemmer))},e.da.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.da.trimmer=e.trimmerSupport.generateTrimmer(e.da.wordCharacters),e.Pipeline.registerFunction(e.da.trimmer,"trimmer-da"),e.da.stemmer=function(){var r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){function e(){var e,r=f.cursor+3;if(d=f.limit,0<=r&&r<=f.limit){for(a=r;;){if(e=f.cursor,f.in_grouping(w,97,248)){f.cursor=e;break}if(f.cursor=e,e>=f.limit)return;f.cursor++}for(;!f.out_grouping(w,97,248);){if(f.cursor>=f.limit)return;f.cursor++}d=f.cursor,d=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(c,32),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del();break;case 2:f.in_grouping_b(p,97,229)&&f.slice_del()}}function t(){var e,r=f.limit-f.cursor;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.find_among_b(l,4)?(f.bra=f.cursor,f.limit_backward=e,f.cursor=f.limit-r,f.cursor>f.limit_backward&&(f.cursor--,f.bra=f.cursor,f.slice_del())):f.limit_backward=e)}function s(){var e,r,i,n=f.limit-f.cursor;if(f.ket=f.cursor,f.eq_s_b(2,"st")&&(f.bra=f.cursor,f.eq_s_b(2,"ig")&&f.slice_del()),f.cursor=f.limit-n,f.cursor>=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(m,5),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del(),i=f.limit-f.cursor,t(),f.cursor=f.limit-i;break;case 2:f.slice_from("løs")}}function o(){var e;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.out_grouping_b(w,97,248)?(f.bra=f.cursor,u=f.slice_to(u),f.limit_backward=e,f.eq_v_b(u)&&f.slice_del()):f.limit_backward=e)}var a,d,u,c=[new r("hed",-1,1),new r("ethed",0,1),new r("ered",-1,1),new r("e",-1,1),new r("erede",3,1),new r("ende",3,1),new r("erende",5,1),new r("ene",3,1),new r("erne",3,1),new r("ere",3,1),new r("en",-1,1),new r("heden",10,1),new r("eren",10,1),new r("er",-1,1),new r("heder",13,1),new r("erer",13,1),new r("s",-1,2),new r("heds",16,1),new r("es",16,1),new r("endes",18,1),new r("erendes",19,1),new r("enes",18,1),new r("ernes",18,1),new r("eres",18,1),new r("ens",16,1),new r("hedens",24,1),new r("erens",24,1),new r("ers",16,1),new r("ets",16,1),new r("erets",28,1),new r("et",-1,1),new r("eret",30,1)],l=[new r("gd",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("elig",1,1),new r("els",-1,1),new r("løst",-1,2)],w=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],p=[239,254,42,3,0,0,0,0,0,0,0,0,0,0,0,0,16],f=new i;this.setCurrent=function(e){f.setCurrent(e)},this.getCurrent=function(){return f.getCurrent()},this.stem=function(){var r=f.cursor;return e(),f.limit_backward=r,f.cursor=f.limit,n(),f.cursor=f.limit,t(),f.cursor=f.limit,s(),f.cursor=f.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.da.stemmer,"stemmer-da"),e.da.stopWordFilter=e.generateStopWordFilter("ad af alle alt anden at blev blive bliver da de dem den denne der deres det dette dig din disse dog du efter eller en end er et for fra ham han hans har havde have hende hendes her hos hun hvad hvis hvor i ikke ind jeg jer jo kunne man mange med meget men mig min mine mit mod ned noget nogle nu når og også om op os over på selv sig sin sine sit skal skulle som sådan thi til ud under var vi vil ville vor være været".split(" ")),e.Pipeline.registerFunction(e.da.stopWordFilter,"stopWordFilter-da")}}); -------------------------------------------------------------------------------- /docs/site/assets/javascripts/lunr/min/lunr.de.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `German` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.de=function(){this.pipeline.reset(),this.pipeline.add(e.de.trimmer,e.de.stopWordFilter,e.de.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.de.stemmer))},e.de.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.de.trimmer=e.trimmerSupport.generateTrimmer(e.de.wordCharacters),e.Pipeline.registerFunction(e.de.trimmer,"trimmer-de"),e.de.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(e,r,n){return!(!v.eq_s(1,e)||(v.ket=v.cursor,!v.in_grouping(p,97,252)))&&(v.slice_from(r),v.cursor=n,!0)}function i(){for(var r,n,i,s,t=v.cursor;;)if(r=v.cursor,v.bra=r,v.eq_s(1,"ß"))v.ket=v.cursor,v.slice_from("ss");else{if(r>=v.limit)break;v.cursor=r+1}for(v.cursor=t;;)for(n=v.cursor;;){if(i=v.cursor,v.in_grouping(p,97,252)){if(s=v.cursor,v.bra=s,e("u","U",i))break;if(v.cursor=s,e("y","Y",i))break}if(i>=v.limit)return void(v.cursor=n);v.cursor=i+1}}function s(){for(;!v.in_grouping(p,97,252);){if(v.cursor>=v.limit)return!0;v.cursor++}for(;!v.out_grouping(p,97,252);){if(v.cursor>=v.limit)return!0;v.cursor++}return!1}function t(){m=v.limit,l=m;var e=v.cursor+3;0<=e&&e<=v.limit&&(d=e,s()||(m=v.cursor,m=v.limit)return;v.cursor++}}}function c(){return m<=v.cursor}function u(){return l<=v.cursor}function a(){var e,r,n,i,s=v.limit-v.cursor;if(v.ket=v.cursor,(e=v.find_among_b(w,7))&&(v.bra=v.cursor,c()))switch(e){case 1:v.slice_del();break;case 2:v.slice_del(),v.ket=v.cursor,v.eq_s_b(1,"s")&&(v.bra=v.cursor,v.eq_s_b(3,"nis")&&v.slice_del());break;case 3:v.in_grouping_b(g,98,116)&&v.slice_del()}if(v.cursor=v.limit-s,v.ket=v.cursor,(e=v.find_among_b(f,4))&&(v.bra=v.cursor,c()))switch(e){case 1:v.slice_del();break;case 2:if(v.in_grouping_b(k,98,116)){var t=v.cursor-3;v.limit_backward<=t&&t<=v.limit&&(v.cursor=t,v.slice_del())}}if(v.cursor=v.limit-s,v.ket=v.cursor,(e=v.find_among_b(_,8))&&(v.bra=v.cursor,u()))switch(e){case 1:v.slice_del(),v.ket=v.cursor,v.eq_s_b(2,"ig")&&(v.bra=v.cursor,r=v.limit-v.cursor,v.eq_s_b(1,"e")||(v.cursor=v.limit-r,u()&&v.slice_del()));break;case 2:n=v.limit-v.cursor,v.eq_s_b(1,"e")||(v.cursor=v.limit-n,v.slice_del());break;case 3:if(v.slice_del(),v.ket=v.cursor,i=v.limit-v.cursor,!v.eq_s_b(2,"er")&&(v.cursor=v.limit-i,!v.eq_s_b(2,"en")))break;v.bra=v.cursor,c()&&v.slice_del();break;case 4:v.slice_del(),v.ket=v.cursor,e=v.find_among_b(b,2),e&&(v.bra=v.cursor,u()&&1==e&&v.slice_del())}}var d,l,m,h=[new r("",-1,6),new r("U",0,2),new r("Y",0,1),new r("ä",0,3),new r("ö",0,4),new r("ü",0,5)],w=[new r("e",-1,2),new r("em",-1,1),new r("en",-1,2),new r("ern",-1,1),new r("er",-1,1),new r("s",-1,3),new r("es",5,2)],f=[new r("en",-1,1),new r("er",-1,1),new r("st",-1,2),new r("est",2,1)],b=[new r("ig",-1,1),new r("lich",-1,1)],_=[new r("end",-1,1),new r("ig",-1,2),new r("ung",-1,1),new r("lich",-1,3),new r("isch",-1,2),new r("ik",-1,2),new r("heit",-1,3),new r("keit",-1,4)],p=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32,8],g=[117,30,5],k=[117,30,4],v=new n;this.setCurrent=function(e){v.setCurrent(e)},this.getCurrent=function(){return v.getCurrent()},this.stem=function(){var e=v.cursor;return i(),v.cursor=e,t(),v.limit_backward=e,v.cursor=v.limit,a(),v.cursor=v.limit_backward,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.de.stemmer,"stemmer-de"),e.de.stopWordFilter=e.generateStopWordFilter("aber alle allem allen aller alles als also am an ander andere anderem anderen anderer anderes anderm andern anderr anders auch auf aus bei bin bis bist da damit dann das dasselbe dazu daß dein deine deinem deinen deiner deines dem demselben den denn denselben der derer derselbe derselben des desselben dessen dich die dies diese dieselbe dieselben diesem diesen dieser dieses dir doch dort du durch ein eine einem einen einer eines einig einige einigem einigen einiger einiges einmal er es etwas euch euer eure eurem euren eurer eures für gegen gewesen hab habe haben hat hatte hatten hier hin hinter ich ihm ihn ihnen ihr ihre ihrem ihren ihrer ihres im in indem ins ist jede jedem jeden jeder jedes jene jenem jenen jener jenes jetzt kann kein keine keinem keinen keiner keines können könnte machen man manche manchem manchen mancher manches mein meine meinem meinen meiner meines mich mir mit muss musste nach nicht nichts noch nun nur ob oder ohne sehr sein seine seinem seinen seiner seines selbst sich sie sind so solche solchem solchen solcher solches soll sollte sondern sonst um und uns unse unsem unsen unser unses unter viel vom von vor war waren warst was weg weil weiter welche welchem welchen welcher welches wenn werde werden wie wieder will wir wird wirst wo wollen wollte während würde würden zu zum zur zwar zwischen über".split(" ")),e.Pipeline.registerFunction(e.de.stopWordFilter,"stopWordFilter-de")}}); -------------------------------------------------------------------------------- /docs/site/assets/javascripts/lunr/min/lunr.du.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Dutch` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");console.warn('[Lunr Languages] Please use the "nl" instead of the "du". The "nl" code is the standard code for Dutch language, and "du" will be removed in the next major versions.'),e.du=function(){this.pipeline.reset(),this.pipeline.add(e.du.trimmer,e.du.stopWordFilter,e.du.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.du.stemmer))},e.du.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.du.trimmer=e.trimmerSupport.generateTrimmer(e.du.wordCharacters),e.Pipeline.registerFunction(e.du.trimmer,"trimmer-du"),e.du.stemmer=function(){var r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){function e(){for(var e,r,i,o=C.cursor;;){if(C.bra=C.cursor,e=C.find_among(b,11))switch(C.ket=C.cursor,e){case 1:C.slice_from("a");continue;case 2:C.slice_from("e");continue;case 3:C.slice_from("i");continue;case 4:C.slice_from("o");continue;case 5:C.slice_from("u");continue;case 6:if(C.cursor>=C.limit)break;C.cursor++;continue}break}for(C.cursor=o,C.bra=o,C.eq_s(1,"y")?(C.ket=C.cursor,C.slice_from("Y")):C.cursor=o;;)if(r=C.cursor,C.in_grouping(q,97,232)){if(i=C.cursor,C.bra=i,C.eq_s(1,"i"))C.ket=C.cursor,C.in_grouping(q,97,232)&&(C.slice_from("I"),C.cursor=r);else if(C.cursor=i,C.eq_s(1,"y"))C.ket=C.cursor,C.slice_from("Y"),C.cursor=r;else if(n(r))break}else if(n(r))break}function n(e){return C.cursor=e,e>=C.limit||(C.cursor++,!1)}function o(){_=C.limit,f=_,t()||(_=C.cursor,_<3&&(_=3),t()||(f=C.cursor))}function t(){for(;!C.in_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}for(;!C.out_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}return!1}function s(){for(var e;;)if(C.bra=C.cursor,e=C.find_among(p,3))switch(C.ket=C.cursor,e){case 1:C.slice_from("y");break;case 2:C.slice_from("i");break;case 3:if(C.cursor>=C.limit)return;C.cursor++}}function u(){return _<=C.cursor}function c(){return f<=C.cursor}function a(){var e=C.limit-C.cursor;C.find_among_b(g,3)&&(C.cursor=C.limit-e,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del()))}function l(){var e;w=!1,C.ket=C.cursor,C.eq_s_b(1,"e")&&(C.bra=C.cursor,u()&&(e=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-e,C.slice_del(),w=!0,a())))}function m(){var e;u()&&(e=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-e,C.eq_s_b(3,"gem")||(C.cursor=C.limit-e,C.slice_del(),a())))}function d(){var e,r,i,n,o,t,s=C.limit-C.cursor;if(C.ket=C.cursor,e=C.find_among_b(h,5))switch(C.bra=C.cursor,e){case 1:u()&&C.slice_from("heid");break;case 2:m();break;case 3:u()&&C.out_grouping_b(z,97,232)&&C.slice_del()}if(C.cursor=C.limit-s,l(),C.cursor=C.limit-s,C.ket=C.cursor,C.eq_s_b(4,"heid")&&(C.bra=C.cursor,c()&&(r=C.limit-C.cursor,C.eq_s_b(1,"c")||(C.cursor=C.limit-r,C.slice_del(),C.ket=C.cursor,C.eq_s_b(2,"en")&&(C.bra=C.cursor,m())))),C.cursor=C.limit-s,C.ket=C.cursor,e=C.find_among_b(k,6))switch(C.bra=C.cursor,e){case 1:if(c()){if(C.slice_del(),i=C.limit-C.cursor,C.ket=C.cursor,C.eq_s_b(2,"ig")&&(C.bra=C.cursor,c()&&(n=C.limit-C.cursor,!C.eq_s_b(1,"e")))){C.cursor=C.limit-n,C.slice_del();break}C.cursor=C.limit-i,a()}break;case 2:c()&&(o=C.limit-C.cursor,C.eq_s_b(1,"e")||(C.cursor=C.limit-o,C.slice_del()));break;case 3:c()&&(C.slice_del(),l());break;case 4:c()&&C.slice_del();break;case 5:c()&&w&&C.slice_del()}C.cursor=C.limit-s,C.out_grouping_b(j,73,232)&&(t=C.limit-C.cursor,C.find_among_b(v,4)&&C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-t,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del())))}var f,_,w,b=[new r("",-1,6),new r("á",0,1),new r("ä",0,1),new r("é",0,2),new r("ë",0,2),new r("í",0,3),new r("ï",0,3),new r("ó",0,4),new r("ö",0,4),new r("ú",0,5),new r("ü",0,5)],p=[new r("",-1,3),new r("I",0,2),new r("Y",0,1)],g=[new r("dd",-1,-1),new r("kk",-1,-1),new r("tt",-1,-1)],h=[new r("ene",-1,2),new r("se",-1,3),new r("en",-1,2),new r("heden",2,1),new r("s",-1,3)],k=[new r("end",-1,1),new r("ig",-1,2),new r("ing",-1,1),new r("lijk",-1,3),new r("baar",-1,4),new r("bar",-1,5)],v=[new r("aa",-1,-1),new r("ee",-1,-1),new r("oo",-1,-1),new r("uu",-1,-1)],q=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],j=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],z=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],C=new i;this.setCurrent=function(e){C.setCurrent(e)},this.getCurrent=function(){return C.getCurrent()},this.stem=function(){var r=C.cursor;return e(),C.cursor=r,o(),C.limit_backward=r,C.cursor=C.limit,d(),C.cursor=C.limit_backward,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.du.stemmer,"stemmer-du"),e.du.stopWordFilter=e.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),e.Pipeline.registerFunction(e.du.stopWordFilter,"stopWordFilter-du")}}); -------------------------------------------------------------------------------- /docs/site/assets/javascripts/lunr/min/lunr.fi.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Finnish` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(i,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e():e()(i.lunr)}(this,function(){return function(i){if(void 0===i)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===i.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");i.fi=function(){this.pipeline.reset(),this.pipeline.add(i.fi.trimmer,i.fi.stopWordFilter,i.fi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(i.fi.stemmer))},i.fi.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",i.fi.trimmer=i.trimmerSupport.generateTrimmer(i.fi.wordCharacters),i.Pipeline.registerFunction(i.fi.trimmer,"trimmer-fi"),i.fi.stemmer=function(){var e=i.stemmerSupport.Among,r=i.stemmerSupport.SnowballProgram,n=new function(){function i(){f=A.limit,d=f,n()||(f=A.cursor,n()||(d=A.cursor))}function n(){for(var i;;){if(i=A.cursor,A.in_grouping(W,97,246))break;if(A.cursor=i,i>=A.limit)return!0;A.cursor++}for(A.cursor=i;!A.out_grouping(W,97,246);){if(A.cursor>=A.limit)return!0;A.cursor++}return!1}function t(){return d<=A.cursor}function s(){var i,e;if(A.cursor>=f)if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,i=A.find_among_b(h,10)){switch(A.bra=A.cursor,A.limit_backward=e,i){case 1:if(!A.in_grouping_b(x,97,246))return;break;case 2:if(!t())return}A.slice_del()}else A.limit_backward=e}function o(){var i,e,r;if(A.cursor>=f)if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,i=A.find_among_b(v,9))switch(A.bra=A.cursor,A.limit_backward=e,i){case 1:r=A.limit-A.cursor,A.eq_s_b(1,"k")||(A.cursor=A.limit-r,A.slice_del());break;case 2:A.slice_del(),A.ket=A.cursor,A.eq_s_b(3,"kse")&&(A.bra=A.cursor,A.slice_from("ksi"));break;case 3:A.slice_del();break;case 4:A.find_among_b(p,6)&&A.slice_del();break;case 5:A.find_among_b(g,6)&&A.slice_del();break;case 6:A.find_among_b(j,2)&&A.slice_del()}else A.limit_backward=e}function l(){return A.find_among_b(q,7)}function a(){return A.eq_s_b(1,"i")&&A.in_grouping_b(L,97,246)}function u(){var i,e,r;if(A.cursor>=f)if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,i=A.find_among_b(C,30)){switch(A.bra=A.cursor,A.limit_backward=e,i){case 1:if(!A.eq_s_b(1,"a"))return;break;case 2:case 9:if(!A.eq_s_b(1,"e"))return;break;case 3:if(!A.eq_s_b(1,"i"))return;break;case 4:if(!A.eq_s_b(1,"o"))return;break;case 5:if(!A.eq_s_b(1,"ä"))return;break;case 6:if(!A.eq_s_b(1,"ö"))return;break;case 7:if(r=A.limit-A.cursor,!l()&&(A.cursor=A.limit-r,!A.eq_s_b(2,"ie"))){A.cursor=A.limit-r;break}if(A.cursor=A.limit-r,A.cursor<=A.limit_backward){A.cursor=A.limit-r;break}A.cursor--,A.bra=A.cursor;break;case 8:if(!A.in_grouping_b(W,97,246)||!A.out_grouping_b(W,97,246))return}A.slice_del(),k=!0}else A.limit_backward=e}function c(){var i,e,r;if(A.cursor>=d)if(e=A.limit_backward,A.limit_backward=d,A.ket=A.cursor,i=A.find_among_b(P,14)){if(A.bra=A.cursor,A.limit_backward=e,1==i){if(r=A.limit-A.cursor,A.eq_s_b(2,"po"))return;A.cursor=A.limit-r}A.slice_del()}else A.limit_backward=e}function m(){var i;A.cursor>=f&&(i=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,A.find_among_b(F,2)?(A.bra=A.cursor,A.limit_backward=i,A.slice_del()):A.limit_backward=i)}function w(){var i,e,r,n,t,s;if(A.cursor>=f){if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,A.eq_s_b(1,"t")&&(A.bra=A.cursor,r=A.limit-A.cursor,A.in_grouping_b(W,97,246)&&(A.cursor=A.limit-r,A.slice_del(),A.limit_backward=e,n=A.limit-A.cursor,A.cursor>=d&&(A.cursor=d,t=A.limit_backward,A.limit_backward=A.cursor,A.cursor=A.limit-n,A.ket=A.cursor,i=A.find_among_b(S,2))))){if(A.bra=A.cursor,A.limit_backward=t,1==i){if(s=A.limit-A.cursor,A.eq_s_b(2,"po"))return;A.cursor=A.limit-s}return void A.slice_del()}A.limit_backward=e}}function _(){var i,e,r,n;if(A.cursor>=f){for(i=A.limit_backward,A.limit_backward=f,e=A.limit-A.cursor,l()&&(A.cursor=A.limit-e,A.ket=A.cursor,A.cursor>A.limit_backward&&(A.cursor--,A.bra=A.cursor,A.slice_del())),A.cursor=A.limit-e,A.ket=A.cursor,A.in_grouping_b(y,97,228)&&(A.bra=A.cursor,A.out_grouping_b(W,97,246)&&A.slice_del()),A.cursor=A.limit-e,A.ket=A.cursor,A.eq_s_b(1,"j")&&(A.bra=A.cursor,r=A.limit-A.cursor,A.eq_s_b(1,"o")?A.slice_del():(A.cursor=A.limit-r,A.eq_s_b(1,"u")&&A.slice_del())),A.cursor=A.limit-e,A.ket=A.cursor,A.eq_s_b(1,"o")&&(A.bra=A.cursor,A.eq_s_b(1,"j")&&A.slice_del()),A.cursor=A.limit-e,A.limit_backward=i;;){if(n=A.limit-A.cursor,A.out_grouping_b(W,97,246)){A.cursor=A.limit-n;break}if(A.cursor=A.limit-n,A.cursor<=A.limit_backward)return;A.cursor--}A.ket=A.cursor,A.cursor>A.limit_backward&&(A.cursor--,A.bra=A.cursor,b=A.slice_to(),A.eq_v_b(b)&&A.slice_del())}}var k,b,d,f,h=[new e("pa",-1,1),new e("sti",-1,2),new e("kaan",-1,1),new e("han",-1,1),new e("kin",-1,1),new e("hän",-1,1),new e("kään",-1,1),new e("ko",-1,1),new e("pä",-1,1),new e("kö",-1,1)],p=[new e("lla",-1,-1),new e("na",-1,-1),new e("ssa",-1,-1),new e("ta",-1,-1),new e("lta",3,-1),new e("sta",3,-1)],g=[new e("llä",-1,-1),new e("nä",-1,-1),new e("ssä",-1,-1),new e("tä",-1,-1),new e("ltä",3,-1),new e("stä",3,-1)],j=[new e("lle",-1,-1),new e("ine",-1,-1)],v=[new e("nsa",-1,3),new e("mme",-1,3),new e("nne",-1,3),new e("ni",-1,2),new e("si",-1,1),new e("an",-1,4),new e("en",-1,6),new e("än",-1,5),new e("nsä",-1,3)],q=[new e("aa",-1,-1),new e("ee",-1,-1),new e("ii",-1,-1),new e("oo",-1,-1),new e("uu",-1,-1),new e("ää",-1,-1),new e("öö",-1,-1)],C=[new e("a",-1,8),new e("lla",0,-1),new e("na",0,-1),new e("ssa",0,-1),new e("ta",0,-1),new e("lta",4,-1),new e("sta",4,-1),new e("tta",4,9),new e("lle",-1,-1),new e("ine",-1,-1),new e("ksi",-1,-1),new e("n",-1,7),new e("han",11,1),new e("den",11,-1,a),new e("seen",11,-1,l),new e("hen",11,2),new e("tten",11,-1,a),new e("hin",11,3),new e("siin",11,-1,a),new e("hon",11,4),new e("hän",11,5),new e("hön",11,6),new e("ä",-1,8),new e("llä",22,-1),new e("nä",22,-1),new e("ssä",22,-1),new e("tä",22,-1),new e("ltä",26,-1),new e("stä",26,-1),new e("ttä",26,9)],P=[new e("eja",-1,-1),new e("mma",-1,1),new e("imma",1,-1),new e("mpa",-1,1),new e("impa",3,-1),new e("mmi",-1,1),new e("immi",5,-1),new e("mpi",-1,1),new e("impi",7,-1),new e("ejä",-1,-1),new e("mmä",-1,1),new e("immä",10,-1),new e("mpä",-1,1),new e("impä",12,-1)],F=[new e("i",-1,-1),new e("j",-1,-1)],S=[new e("mma",-1,1),new e("imma",0,-1)],y=[17,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8],W=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],L=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],x=[17,97,24,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],A=new r;this.setCurrent=function(i){A.setCurrent(i)},this.getCurrent=function(){return A.getCurrent()},this.stem=function(){var e=A.cursor;return i(),k=!1,A.limit_backward=e,A.cursor=A.limit,s(),A.cursor=A.limit,o(),A.cursor=A.limit,u(),A.cursor=A.limit,c(),A.cursor=A.limit,k?(m(),A.cursor=A.limit):(A.cursor=A.limit,w(),A.cursor=A.limit),_(),!0}};return function(i){return"function"==typeof i.update?i.update(function(i){return n.setCurrent(i),n.stem(),n.getCurrent()}):(n.setCurrent(i),n.stem(),n.getCurrent())}}(),i.Pipeline.registerFunction(i.fi.stemmer,"stemmer-fi"),i.fi.stopWordFilter=i.generateStopWordFilter("ei eivät emme en et ette että he heidän heidät heihin heille heillä heiltä heissä heistä heitä hän häneen hänelle hänellä häneltä hänen hänessä hänestä hänet häntä itse ja johon joiden joihin joiksi joilla joille joilta joina joissa joista joita joka joksi jolla jolle jolta jona jonka jos jossa josta jota jotka kanssa keiden keihin keiksi keille keillä keiltä keinä keissä keistä keitä keneen keneksi kenelle kenellä keneltä kenen kenenä kenessä kenestä kenet ketkä ketkä ketä koska kuin kuka kun me meidän meidät meihin meille meillä meiltä meissä meistä meitä mihin miksi mikä mille millä miltä minkä minkä minua minulla minulle minulta minun minussa minusta minut minuun minä minä missä mistä mitkä mitä mukaan mutta ne niiden niihin niiksi niille niillä niiltä niin niin niinä niissä niistä niitä noiden noihin noiksi noilla noille noilta noin noina noissa noista noita nuo nyt näiden näihin näiksi näille näillä näiltä näinä näissä näistä näitä nämä ole olemme olen olet olette oli olimme olin olisi olisimme olisin olisit olisitte olisivat olit olitte olivat olla olleet ollut on ovat poikki se sekä sen siihen siinä siitä siksi sille sillä sillä siltä sinua sinulla sinulle sinulta sinun sinussa sinusta sinut sinuun sinä sinä sitä tai te teidän teidät teihin teille teillä teiltä teissä teistä teitä tuo tuohon tuoksi tuolla tuolle tuolta tuon tuona tuossa tuosta tuota tähän täksi tälle tällä tältä tämä tämän tänä tässä tästä tätä vaan vai vaikka yli".split(" ")),i.Pipeline.registerFunction(i.fi.stopWordFilter,"stopWordFilter-fi")}}); -------------------------------------------------------------------------------- /docs/site/assets/javascripts/lunr/min/lunr.fr.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `French` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.fr=function(){this.pipeline.reset(),this.pipeline.add(e.fr.trimmer,e.fr.stopWordFilter,e.fr.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.fr.stemmer))},e.fr.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.fr.trimmer=e.trimmerSupport.generateTrimmer(e.fr.wordCharacters),e.Pipeline.registerFunction(e.fr.trimmer,"trimmer-fr"),e.fr.stemmer=function(){var r=e.stemmerSupport.Among,s=e.stemmerSupport.SnowballProgram,i=new function(){function e(e,r,s){return!(!W.eq_s(1,e)||(W.ket=W.cursor,!W.in_grouping(F,97,251)))&&(W.slice_from(r),W.cursor=s,!0)}function i(e,r,s){return!!W.eq_s(1,e)&&(W.ket=W.cursor,W.slice_from(r),W.cursor=s,!0)}function n(){for(var r,s;;){if(r=W.cursor,W.in_grouping(F,97,251)){if(W.bra=W.cursor,s=W.cursor,e("u","U",r))continue;if(W.cursor=s,e("i","I",r))continue;if(W.cursor=s,i("y","Y",r))continue}if(W.cursor=r,W.bra=r,!e("y","Y",r)){if(W.cursor=r,W.eq_s(1,"q")&&(W.bra=W.cursor,i("u","U",r)))continue;if(W.cursor=r,r>=W.limit)return;W.cursor++}}}function t(){for(;!W.in_grouping(F,97,251);){if(W.cursor>=W.limit)return!0;W.cursor++}for(;!W.out_grouping(F,97,251);){if(W.cursor>=W.limit)return!0;W.cursor++}return!1}function u(){var e=W.cursor;if(q=W.limit,g=q,p=q,W.in_grouping(F,97,251)&&W.in_grouping(F,97,251)&&W.cursor=W.limit){W.cursor=q;break}W.cursor++}while(!W.in_grouping(F,97,251))}q=W.cursor,W.cursor=e,t()||(g=W.cursor,t()||(p=W.cursor))}function o(){for(var e,r;;){if(r=W.cursor,W.bra=r,!(e=W.find_among(h,4)))break;switch(W.ket=W.cursor,e){case 1:W.slice_from("i");break;case 2:W.slice_from("u");break;case 3:W.slice_from("y");break;case 4:if(W.cursor>=W.limit)return;W.cursor++}}}function c(){return q<=W.cursor}function a(){return g<=W.cursor}function l(){return p<=W.cursor}function w(){var e,r;if(W.ket=W.cursor,e=W.find_among_b(C,43)){switch(W.bra=W.cursor,e){case 1:if(!l())return!1;W.slice_del();break;case 2:if(!l())return!1;W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"ic")&&(W.bra=W.cursor,l()?W.slice_del():W.slice_from("iqU"));break;case 3:if(!l())return!1;W.slice_from("log");break;case 4:if(!l())return!1;W.slice_from("u");break;case 5:if(!l())return!1;W.slice_from("ent");break;case 6:if(!c())return!1;if(W.slice_del(),W.ket=W.cursor,e=W.find_among_b(z,6))switch(W.bra=W.cursor,e){case 1:l()&&(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"at")&&(W.bra=W.cursor,l()&&W.slice_del()));break;case 2:l()?W.slice_del():a()&&W.slice_from("eux");break;case 3:l()&&W.slice_del();break;case 4:c()&&W.slice_from("i")}break;case 7:if(!l())return!1;if(W.slice_del(),W.ket=W.cursor,e=W.find_among_b(y,3))switch(W.bra=W.cursor,e){case 1:l()?W.slice_del():W.slice_from("abl");break;case 2:l()?W.slice_del():W.slice_from("iqU");break;case 3:l()&&W.slice_del()}break;case 8:if(!l())return!1;if(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"at")&&(W.bra=W.cursor,l()&&(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"ic")))){W.bra=W.cursor,l()?W.slice_del():W.slice_from("iqU");break}break;case 9:W.slice_from("eau");break;case 10:if(!a())return!1;W.slice_from("al");break;case 11:if(l())W.slice_del();else{if(!a())return!1;W.slice_from("eux")}break;case 12:if(!a()||!W.out_grouping_b(F,97,251))return!1;W.slice_del();break;case 13:return c()&&W.slice_from("ant"),!1;case 14:return c()&&W.slice_from("ent"),!1;case 15:return r=W.limit-W.cursor,W.in_grouping_b(F,97,251)&&c()&&(W.cursor=W.limit-r,W.slice_del()),!1}return!0}return!1}function f(){var e,r;if(W.cursor=q){if(s=W.limit_backward,W.limit_backward=q,W.ket=W.cursor,e=W.find_among_b(P,7))switch(W.bra=W.cursor,e){case 1:if(l()){if(i=W.limit-W.cursor,!W.eq_s_b(1,"s")&&(W.cursor=W.limit-i,!W.eq_s_b(1,"t")))break;W.slice_del()}break;case 2:W.slice_from("i");break;case 3:W.slice_del();break;case 4:W.eq_s_b(2,"gu")&&W.slice_del()}W.limit_backward=s}}function b(){var e=W.limit-W.cursor;W.find_among_b(U,5)&&(W.cursor=W.limit-e,W.ket=W.cursor,W.cursor>W.limit_backward&&(W.cursor--,W.bra=W.cursor,W.slice_del()))}function d(){for(var e,r=1;W.out_grouping_b(F,97,251);)r--;if(r<=0){if(W.ket=W.cursor,e=W.limit-W.cursor,!W.eq_s_b(1,"é")&&(W.cursor=W.limit-e,!W.eq_s_b(1,"è")))return;W.bra=W.cursor,W.slice_from("e")}}function k(){if(!w()&&(W.cursor=W.limit,!f()&&(W.cursor=W.limit,!m())))return W.cursor=W.limit,void _();W.cursor=W.limit,W.ket=W.cursor,W.eq_s_b(1,"Y")?(W.bra=W.cursor,W.slice_from("i")):(W.cursor=W.limit,W.eq_s_b(1,"ç")&&(W.bra=W.cursor,W.slice_from("c")))}var p,g,q,v=[new r("col",-1,-1),new r("par",-1,-1),new r("tap",-1,-1)],h=[new r("",-1,4),new r("I",0,1),new r("U",0,2),new r("Y",0,3)],z=[new r("iqU",-1,3),new r("abl",-1,3),new r("Ièr",-1,4),new r("ièr",-1,4),new r("eus",-1,2),new r("iv",-1,1)],y=[new r("ic",-1,2),new r("abil",-1,1),new r("iv",-1,3)],C=[new r("iqUe",-1,1),new r("atrice",-1,2),new r("ance",-1,1),new r("ence",-1,5),new r("logie",-1,3),new r("able",-1,1),new r("isme",-1,1),new r("euse",-1,11),new r("iste",-1,1),new r("ive",-1,8),new r("if",-1,8),new r("usion",-1,4),new r("ation",-1,2),new r("ution",-1,4),new r("ateur",-1,2),new r("iqUes",-1,1),new r("atrices",-1,2),new r("ances",-1,1),new r("ences",-1,5),new r("logies",-1,3),new r("ables",-1,1),new r("ismes",-1,1),new r("euses",-1,11),new r("istes",-1,1),new r("ives",-1,8),new r("ifs",-1,8),new r("usions",-1,4),new r("ations",-1,2),new r("utions",-1,4),new r("ateurs",-1,2),new r("ments",-1,15),new r("ements",30,6),new r("issements",31,12),new r("ités",-1,7),new r("ment",-1,15),new r("ement",34,6),new r("issement",35,12),new r("amment",34,13),new r("emment",34,14),new r("aux",-1,10),new r("eaux",39,9),new r("eux",-1,1),new r("ité",-1,7)],x=[new r("ira",-1,1),new r("ie",-1,1),new r("isse",-1,1),new r("issante",-1,1),new r("i",-1,1),new r("irai",4,1),new r("ir",-1,1),new r("iras",-1,1),new r("ies",-1,1),new r("îmes",-1,1),new r("isses",-1,1),new r("issantes",-1,1),new r("îtes",-1,1),new r("is",-1,1),new r("irais",13,1),new r("issais",13,1),new r("irions",-1,1),new r("issions",-1,1),new r("irons",-1,1),new r("issons",-1,1),new r("issants",-1,1),new r("it",-1,1),new r("irait",21,1),new r("issait",21,1),new r("issant",-1,1),new r("iraIent",-1,1),new r("issaIent",-1,1),new r("irent",-1,1),new r("issent",-1,1),new r("iront",-1,1),new r("ît",-1,1),new r("iriez",-1,1),new r("issiez",-1,1),new r("irez",-1,1),new r("issez",-1,1)],I=[new r("a",-1,3),new r("era",0,2),new r("asse",-1,3),new r("ante",-1,3),new r("ée",-1,2),new r("ai",-1,3),new r("erai",5,2),new r("er",-1,2),new r("as",-1,3),new r("eras",8,2),new r("âmes",-1,3),new r("asses",-1,3),new r("antes",-1,3),new r("âtes",-1,3),new r("ées",-1,2),new r("ais",-1,3),new r("erais",15,2),new r("ions",-1,1),new r("erions",17,2),new r("assions",17,3),new r("erons",-1,2),new r("ants",-1,3),new r("és",-1,2),new r("ait",-1,3),new r("erait",23,2),new r("ant",-1,3),new r("aIent",-1,3),new r("eraIent",26,2),new r("èrent",-1,2),new r("assent",-1,3),new r("eront",-1,2),new r("ât",-1,3),new r("ez",-1,2),new r("iez",32,2),new r("eriez",33,2),new r("assiez",33,3),new r("erez",32,2),new r("é",-1,2)],P=[new r("e",-1,3),new r("Ière",0,2),new r("ière",0,2),new r("ion",-1,1),new r("Ier",-1,2),new r("ier",-1,2),new r("ë",-1,4)],U=[new r("ell",-1,-1),new r("eill",-1,-1),new r("enn",-1,-1),new r("onn",-1,-1),new r("ett",-1,-1)],F=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,128,130,103,8,5],S=[1,65,20,0,0,0,0,0,0,0,0,0,0,0,0,0,128],W=new s;this.setCurrent=function(e){W.setCurrent(e)},this.getCurrent=function(){return W.getCurrent()},this.stem=function(){var e=W.cursor;return n(),W.cursor=e,u(),W.limit_backward=e,W.cursor=W.limit,k(),W.cursor=W.limit,b(),W.cursor=W.limit,d(),W.cursor=W.limit_backward,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.fr.stemmer,"stemmer-fr"),e.fr.stopWordFilter=e.generateStopWordFilter("ai aie aient aies ait as au aura aurai auraient aurais aurait auras aurez auriez aurions aurons auront aux avaient avais avait avec avez aviez avions avons ayant ayez ayons c ce ceci celà ces cet cette d dans de des du elle en es est et eu eue eues eurent eus eusse eussent eusses eussiez eussions eut eux eûmes eût eûtes furent fus fusse fussent fusses fussiez fussions fut fûmes fût fûtes ici il ils j je l la le les leur leurs lui m ma mais me mes moi mon même n ne nos notre nous on ont ou par pas pour qu que quel quelle quelles quels qui s sa sans se sera serai seraient serais serait seras serez seriez serions serons seront ses soi soient sois soit sommes son sont soyez soyons suis sur t ta te tes toi ton tu un une vos votre vous y à étaient étais était étant étiez étions été étée étées étés êtes".split(" ")),e.Pipeline.registerFunction(e.fr.stopWordFilter,"stopWordFilter-fr")}}); -------------------------------------------------------------------------------- /docs/site/assets/javascripts/lunr/min/lunr.hu.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Hungarian` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n():n()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hu=function(){this.pipeline.reset(),this.pipeline.add(e.hu.trimmer,e.hu.stopWordFilter,e.hu.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hu.stemmer))},e.hu.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.hu.trimmer=e.trimmerSupport.generateTrimmer(e.hu.wordCharacters),e.Pipeline.registerFunction(e.hu.trimmer,"trimmer-hu"),e.hu.stemmer=function(){var n=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,i=new function(){function e(){var e,n=L.cursor;if(d=L.limit,L.in_grouping(W,97,252))for(;;){if(e=L.cursor,L.out_grouping(W,97,252))return L.cursor=e,L.find_among(g,8)||(L.cursor=e,e=L.limit)return void(d=e);L.cursor++}if(L.cursor=n,L.out_grouping(W,97,252)){for(;!L.in_grouping(W,97,252);){if(L.cursor>=L.limit)return;L.cursor++}d=L.cursor}}function i(){return d<=L.cursor}function a(){var e;if(L.ket=L.cursor,(e=L.find_among_b(h,2))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("a");break;case 2:L.slice_from("e")}}function t(){var e=L.limit-L.cursor;return!!L.find_among_b(p,23)&&(L.cursor=L.limit-e,!0)}function s(){if(L.cursor>L.limit_backward){L.cursor--,L.ket=L.cursor;var e=L.cursor-1;L.limit_backward<=e&&e<=L.limit&&(L.cursor=e,L.bra=e,L.slice_del())}}function c(){var e;if(L.ket=L.cursor,(e=L.find_among_b(_,2))&&(L.bra=L.cursor,i())){if((1==e||2==e)&&!t())return;L.slice_del(),s()}}function o(){L.ket=L.cursor,L.find_among_b(v,44)&&(L.bra=L.cursor,i()&&(L.slice_del(),a()))}function w(){var e;if(L.ket=L.cursor,(e=L.find_among_b(z,3))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("e");break;case 2:case 3:L.slice_from("a")}}function l(){var e;if(L.ket=L.cursor,(e=L.find_among_b(y,6))&&(L.bra=L.cursor,i()))switch(e){case 1:case 2:L.slice_del();break;case 3:L.slice_from("a");break;case 4:L.slice_from("e")}}function u(){var e;if(L.ket=L.cursor,(e=L.find_among_b(j,2))&&(L.bra=L.cursor,i())){if((1==e||2==e)&&!t())return;L.slice_del(),s()}}function m(){var e;if(L.ket=L.cursor,(e=L.find_among_b(C,7))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("a");break;case 2:L.slice_from("e");break;case 3:case 4:case 5:case 6:case 7:L.slice_del()}}function k(){var e;if(L.ket=L.cursor,(e=L.find_among_b(P,12))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 7:case 9:L.slice_del();break;case 2:case 5:case 8:L.slice_from("e");break;case 3:case 6:L.slice_from("a")}}function f(){var e;if(L.ket=L.cursor,(e=L.find_among_b(F,31))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 7:case 8:case 9:case 12:case 13:case 16:case 17:case 18:L.slice_del();break;case 2:case 5:case 10:case 14:case 19:L.slice_from("a");break;case 3:case 6:case 11:case 15:case 20:L.slice_from("e")}}function b(){var e;if(L.ket=L.cursor,(e=L.find_among_b(S,42))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 5:case 6:case 9:case 10:case 11:case 14:case 15:case 16:case 17:case 20:case 21:case 24:case 25:case 26:case 29:L.slice_del();break;case 2:case 7:case 12:case 18:case 22:case 27:L.slice_from("a");break;case 3:case 8:case 13:case 19:case 23:case 28:L.slice_from("e")}}var d,g=[new n("cs",-1,-1),new n("dzs",-1,-1),new n("gy",-1,-1),new n("ly",-1,-1),new n("ny",-1,-1),new n("sz",-1,-1),new n("ty",-1,-1),new n("zs",-1,-1)],h=[new n("á",-1,1),new n("é",-1,2)],p=[new n("bb",-1,-1),new n("cc",-1,-1),new n("dd",-1,-1),new n("ff",-1,-1),new n("gg",-1,-1),new n("jj",-1,-1),new n("kk",-1,-1),new n("ll",-1,-1),new n("mm",-1,-1),new n("nn",-1,-1),new n("pp",-1,-1),new n("rr",-1,-1),new n("ccs",-1,-1),new n("ss",-1,-1),new n("zzs",-1,-1),new n("tt",-1,-1),new n("vv",-1,-1),new n("ggy",-1,-1),new n("lly",-1,-1),new n("nny",-1,-1),new n("tty",-1,-1),new n("ssz",-1,-1),new n("zz",-1,-1)],_=[new n("al",-1,1),new n("el",-1,2)],v=[new n("ba",-1,-1),new n("ra",-1,-1),new n("be",-1,-1),new n("re",-1,-1),new n("ig",-1,-1),new n("nak",-1,-1),new n("nek",-1,-1),new n("val",-1,-1),new n("vel",-1,-1),new n("ul",-1,-1),new n("nál",-1,-1),new n("nél",-1,-1),new n("ból",-1,-1),new n("ról",-1,-1),new n("tól",-1,-1),new n("bõl",-1,-1),new n("rõl",-1,-1),new n("tõl",-1,-1),new n("ül",-1,-1),new n("n",-1,-1),new n("an",19,-1),new n("ban",20,-1),new n("en",19,-1),new n("ben",22,-1),new n("képpen",22,-1),new n("on",19,-1),new n("ön",19,-1),new n("képp",-1,-1),new n("kor",-1,-1),new n("t",-1,-1),new n("at",29,-1),new n("et",29,-1),new n("ként",29,-1),new n("anként",32,-1),new n("enként",32,-1),new n("onként",32,-1),new n("ot",29,-1),new n("ért",29,-1),new n("öt",29,-1),new n("hez",-1,-1),new n("hoz",-1,-1),new n("höz",-1,-1),new n("vá",-1,-1),new n("vé",-1,-1)],z=[new n("án",-1,2),new n("én",-1,1),new n("ánként",-1,3)],y=[new n("stul",-1,2),new n("astul",0,1),new n("ástul",0,3),new n("stül",-1,2),new n("estül",3,1),new n("éstül",3,4)],j=[new n("á",-1,1),new n("é",-1,2)],C=[new n("k",-1,7),new n("ak",0,4),new n("ek",0,6),new n("ok",0,5),new n("ák",0,1),new n("ék",0,2),new n("ök",0,3)],P=[new n("éi",-1,7),new n("áéi",0,6),new n("ééi",0,5),new n("é",-1,9),new n("ké",3,4),new n("aké",4,1),new n("eké",4,1),new n("oké",4,1),new n("áké",4,3),new n("éké",4,2),new n("öké",4,1),new n("éé",3,8)],F=[new n("a",-1,18),new n("ja",0,17),new n("d",-1,16),new n("ad",2,13),new n("ed",2,13),new n("od",2,13),new n("ád",2,14),new n("éd",2,15),new n("öd",2,13),new n("e",-1,18),new n("je",9,17),new n("nk",-1,4),new n("unk",11,1),new n("ánk",11,2),new n("énk",11,3),new n("ünk",11,1),new n("uk",-1,8),new n("juk",16,7),new n("ájuk",17,5),new n("ük",-1,8),new n("jük",19,7),new n("éjük",20,6),new n("m",-1,12),new n("am",22,9),new n("em",22,9),new n("om",22,9),new n("ám",22,10),new n("ém",22,11),new n("o",-1,18),new n("á",-1,19),new n("é",-1,20)],S=[new n("id",-1,10),new n("aid",0,9),new n("jaid",1,6),new n("eid",0,9),new n("jeid",3,6),new n("áid",0,7),new n("éid",0,8),new n("i",-1,15),new n("ai",7,14),new n("jai",8,11),new n("ei",7,14),new n("jei",10,11),new n("ái",7,12),new n("éi",7,13),new n("itek",-1,24),new n("eitek",14,21),new n("jeitek",15,20),new n("éitek",14,23),new n("ik",-1,29),new n("aik",18,26),new n("jaik",19,25),new n("eik",18,26),new n("jeik",21,25),new n("áik",18,27),new n("éik",18,28),new n("ink",-1,20),new n("aink",25,17),new n("jaink",26,16),new n("eink",25,17),new n("jeink",28,16),new n("áink",25,18),new n("éink",25,19),new n("aitok",-1,21),new n("jaitok",32,20),new n("áitok",-1,22),new n("im",-1,5),new n("aim",35,4),new n("jaim",36,1),new n("eim",35,4),new n("jeim",38,1),new n("áim",35,2),new n("éim",35,3)],W=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,52,14],L=new r;this.setCurrent=function(e){L.setCurrent(e)},this.getCurrent=function(){return L.getCurrent()},this.stem=function(){var n=L.cursor;return e(),L.limit_backward=n,L.cursor=L.limit,c(),L.cursor=L.limit,o(),L.cursor=L.limit,w(),L.cursor=L.limit,l(),L.cursor=L.limit,u(),L.cursor=L.limit,k(),L.cursor=L.limit,f(),L.cursor=L.limit,b(),L.cursor=L.limit,m(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.hu.stemmer,"stemmer-hu"),e.hu.stopWordFilter=e.generateStopWordFilter("a abban ahhoz ahogy ahol aki akik akkor alatt amely amelyek amelyekben amelyeket amelyet amelynek ami amikor amit amolyan amíg annak arra arról az azok azon azonban azt aztán azután azzal azért be belül benne bár cikk cikkek cikkeket csak de e ebben eddig egy egyes egyetlen egyik egyre egyéb egész ehhez ekkor el ellen elsõ elég elõ elõször elõtt emilyen ennek erre ez ezek ezen ezt ezzel ezért fel felé hanem hiszen hogy hogyan igen ill ill. illetve ilyen ilyenkor ismét ison itt jobban jó jól kell kellett keressünk keresztül ki kívül között közül legalább legyen lehet lehetett lenne lenni lesz lett maga magát majd majd meg mellett mely melyek mert mi mikor milyen minden mindenki mindent mindig mint mintha mit mivel miért most már más másik még míg nagy nagyobb nagyon ne nekem neki nem nincs néha néhány nélkül olyan ott pedig persze rá s saját sem semmi sok sokat sokkal szemben szerint szinte számára talán tehát teljes tovább továbbá több ugyanis utolsó után utána vagy vagyis vagyok valaki valami valamint való van vannak vele vissza viszont volna volt voltak voltam voltunk által általában át én éppen és így õ õk õket össze úgy új újabb újra".split(" ")),e.Pipeline.registerFunction(e.hu.stopWordFilter,"stopWordFilter-hu")}}); -------------------------------------------------------------------------------- /docs/site/assets/javascripts/lunr/min/lunr.ja.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.ja=function(){this.pipeline.reset(),this.pipeline.add(e.ja.trimmer,e.ja.stopWordFilter,e.ja.stemmer),r?this.tokenizer=e.ja.tokenizer:(e.tokenizer&&(e.tokenizer=e.ja.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.ja.tokenizer))};var t=new e.TinySegmenter;e.ja.tokenizer=function(i){var n,o,s,p,a,u,m,l,c,f;if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t.toLowerCase()):t.toLowerCase()});for(o=i.toString().toLowerCase().replace(/^\s+/,""),n=o.length-1;n>=0;n--)if(/\S/.test(o.charAt(n))){o=o.substring(0,n+1);break}for(a=[],s=o.length,c=0,l=0;c<=s;c++)if(u=o.charAt(c),m=c-l,u.match(/\s/)||c==s){if(m>0)for(p=t.segment(o.slice(l,c)).filter(function(e){return!!e}),f=l,n=0;n=C.limit)break;C.cursor++;continue}break}for(C.cursor=o,C.bra=o,C.eq_s(1,"y")?(C.ket=C.cursor,C.slice_from("Y")):C.cursor=o;;)if(e=C.cursor,C.in_grouping(q,97,232)){if(i=C.cursor,C.bra=i,C.eq_s(1,"i"))C.ket=C.cursor,C.in_grouping(q,97,232)&&(C.slice_from("I"),C.cursor=e);else if(C.cursor=i,C.eq_s(1,"y"))C.ket=C.cursor,C.slice_from("Y"),C.cursor=e;else if(n(e))break}else if(n(e))break}function n(r){return C.cursor=r,r>=C.limit||(C.cursor++,!1)}function o(){_=C.limit,d=_,t()||(_=C.cursor,_<3&&(_=3),t()||(d=C.cursor))}function t(){for(;!C.in_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}for(;!C.out_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}return!1}function s(){for(var r;;)if(C.bra=C.cursor,r=C.find_among(p,3))switch(C.ket=C.cursor,r){case 1:C.slice_from("y");break;case 2:C.slice_from("i");break;case 3:if(C.cursor>=C.limit)return;C.cursor++}}function u(){return _<=C.cursor}function c(){return d<=C.cursor}function a(){var r=C.limit-C.cursor;C.find_among_b(g,3)&&(C.cursor=C.limit-r,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del()))}function l(){var r;w=!1,C.ket=C.cursor,C.eq_s_b(1,"e")&&(C.bra=C.cursor,u()&&(r=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-r,C.slice_del(),w=!0,a())))}function m(){var r;u()&&(r=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-r,C.eq_s_b(3,"gem")||(C.cursor=C.limit-r,C.slice_del(),a())))}function f(){var r,e,i,n,o,t,s=C.limit-C.cursor;if(C.ket=C.cursor,r=C.find_among_b(h,5))switch(C.bra=C.cursor,r){case 1:u()&&C.slice_from("heid");break;case 2:m();break;case 3:u()&&C.out_grouping_b(j,97,232)&&C.slice_del()}if(C.cursor=C.limit-s,l(),C.cursor=C.limit-s,C.ket=C.cursor,C.eq_s_b(4,"heid")&&(C.bra=C.cursor,c()&&(e=C.limit-C.cursor,C.eq_s_b(1,"c")||(C.cursor=C.limit-e,C.slice_del(),C.ket=C.cursor,C.eq_s_b(2,"en")&&(C.bra=C.cursor,m())))),C.cursor=C.limit-s,C.ket=C.cursor,r=C.find_among_b(k,6))switch(C.bra=C.cursor,r){case 1:if(c()){if(C.slice_del(),i=C.limit-C.cursor,C.ket=C.cursor,C.eq_s_b(2,"ig")&&(C.bra=C.cursor,c()&&(n=C.limit-C.cursor,!C.eq_s_b(1,"e")))){C.cursor=C.limit-n,C.slice_del();break}C.cursor=C.limit-i,a()}break;case 2:c()&&(o=C.limit-C.cursor,C.eq_s_b(1,"e")||(C.cursor=C.limit-o,C.slice_del()));break;case 3:c()&&(C.slice_del(),l());break;case 4:c()&&C.slice_del();break;case 5:c()&&w&&C.slice_del()}C.cursor=C.limit-s,C.out_grouping_b(z,73,232)&&(t=C.limit-C.cursor,C.find_among_b(v,4)&&C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-t,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del())))}var d,_,w,b=[new e("",-1,6),new e("á",0,1),new e("ä",0,1),new e("é",0,2),new e("ë",0,2),new e("í",0,3),new e("ï",0,3),new e("ó",0,4),new e("ö",0,4),new e("ú",0,5),new e("ü",0,5)],p=[new e("",-1,3),new e("I",0,2),new e("Y",0,1)],g=[new e("dd",-1,-1),new e("kk",-1,-1),new e("tt",-1,-1)],h=[new e("ene",-1,2),new e("se",-1,3),new e("en",-1,2),new e("heden",2,1),new e("s",-1,3)],k=[new e("end",-1,1),new e("ig",-1,2),new e("ing",-1,1),new e("lijk",-1,3),new e("baar",-1,4),new e("bar",-1,5)],v=[new e("aa",-1,-1),new e("ee",-1,-1),new e("oo",-1,-1),new e("uu",-1,-1)],q=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],z=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],j=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],C=new i;this.setCurrent=function(r){C.setCurrent(r)},this.getCurrent=function(){return C.getCurrent()},this.stem=function(){var e=C.cursor;return r(),C.cursor=e,o(),C.limit_backward=e,C.cursor=C.limit,f(),C.cursor=C.limit_backward,s(),!0}};return function(r){return"function"==typeof r.update?r.update(function(r){return n.setCurrent(r),n.stem(),n.getCurrent()}):(n.setCurrent(r),n.stem(),n.getCurrent())}}(),r.Pipeline.registerFunction(r.nl.stemmer,"stemmer-nl"),r.nl.stopWordFilter=r.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),r.Pipeline.registerFunction(r.nl.stopWordFilter,"stopWordFilter-nl")}}); -------------------------------------------------------------------------------- /docs/site/assets/javascripts/lunr/min/lunr.no.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Norwegian` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.no=function(){this.pipeline.reset(),this.pipeline.add(e.no.trimmer,e.no.stopWordFilter,e.no.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.no.stemmer))},e.no.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.no.trimmer=e.trimmerSupport.generateTrimmer(e.no.wordCharacters),e.Pipeline.registerFunction(e.no.trimmer,"trimmer-no"),e.no.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(){var e,r=w.cursor+3;if(a=w.limit,0<=r||r<=w.limit){for(s=r;;){if(e=w.cursor,w.in_grouping(d,97,248)){w.cursor=e;break}if(e>=w.limit)return;w.cursor=e+1}for(;!w.out_grouping(d,97,248);){if(w.cursor>=w.limit)return;w.cursor++}a=w.cursor,a=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(m,29),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:n=w.limit-w.cursor,w.in_grouping_b(c,98,122)?w.slice_del():(w.cursor=w.limit-n,w.eq_s_b(1,"k")&&w.out_grouping_b(d,97,248)&&w.slice_del());break;case 3:w.slice_from("er")}}function t(){var e,r=w.limit-w.cursor;w.cursor>=a&&(e=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,w.find_among_b(u,2)?(w.bra=w.cursor,w.limit_backward=e,w.cursor=w.limit-r,w.cursor>w.limit_backward&&(w.cursor--,w.bra=w.cursor,w.slice_del())):w.limit_backward=e)}function o(){var e,r;w.cursor>=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(l,11),e?(w.bra=w.cursor,w.limit_backward=r,1==e&&w.slice_del()):w.limit_backward=r)}var s,a,m=[new r("a",-1,1),new r("e",-1,1),new r("ede",1,1),new r("ande",1,1),new r("ende",1,1),new r("ane",1,1),new r("ene",1,1),new r("hetene",6,1),new r("erte",1,3),new r("en",-1,1),new r("heten",9,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",12,1),new r("s",-1,2),new r("as",14,1),new r("es",14,1),new r("edes",16,1),new r("endes",16,1),new r("enes",16,1),new r("hetenes",19,1),new r("ens",14,1),new r("hetens",21,1),new r("ers",14,1),new r("ets",14,1),new r("et",-1,1),new r("het",25,1),new r("ert",-1,3),new r("ast",-1,1)],u=[new r("dt",-1,-1),new r("vt",-1,-1)],l=[new r("leg",-1,1),new r("eleg",0,1),new r("ig",-1,1),new r("eig",2,1),new r("lig",2,1),new r("elig",4,1),new r("els",-1,1),new r("lov",-1,1),new r("elov",7,1),new r("slov",7,1),new r("hetslov",9,1)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],c=[119,125,149,1],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,i(),w.cursor=w.limit,t(),w.cursor=w.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.no.stemmer,"stemmer-no"),e.no.stopWordFilter=e.generateStopWordFilter("alle at av bare begge ble blei bli blir blitt både båe da de deg dei deim deira deires dem den denne der dere deres det dette di din disse ditt du dykk dykkar då eg ein eit eitt eller elles en enn er et ett etter for fordi fra før ha hadde han hans har hennar henne hennes her hjå ho hoe honom hoss hossen hun hva hvem hver hvilke hvilken hvis hvor hvordan hvorfor i ikke ikkje ikkje ingen ingi inkje inn inni ja jeg kan kom korleis korso kun kunne kva kvar kvarhelst kven kvi kvifor man mange me med medan meg meget mellom men mi min mine mitt mot mykje ned no noe noen noka noko nokon nokor nokre nå når og også om opp oss over på samme seg selv si si sia sidan siden sin sine sitt sjøl skal skulle slik so som som somme somt så sånn til um upp ut uten var vart varte ved vere verte vi vil ville vore vors vort vår være være vært å".split(" ")),e.Pipeline.registerFunction(e.no.stopWordFilter,"stopWordFilter-no")}}); -------------------------------------------------------------------------------- /docs/site/assets/javascripts/lunr/min/lunr.pt.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Portuguese` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.pt=function(){this.pipeline.reset(),this.pipeline.add(e.pt.trimmer,e.pt.stopWordFilter,e.pt.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.pt.stemmer))},e.pt.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.pt.trimmer=e.trimmerSupport.generateTrimmer(e.pt.wordCharacters),e.Pipeline.registerFunction(e.pt.trimmer,"trimmer-pt"),e.pt.stemmer=function(){var r=e.stemmerSupport.Among,s=e.stemmerSupport.SnowballProgram,n=new function(){function e(){for(var e;;){if(z.bra=z.cursor,e=z.find_among(k,3))switch(z.ket=z.cursor,e){case 1:z.slice_from("a~");continue;case 2:z.slice_from("o~");continue;case 3:if(z.cursor>=z.limit)break;z.cursor++;continue}break}}function n(){if(z.out_grouping(y,97,250)){for(;!z.in_grouping(y,97,250);){if(z.cursor>=z.limit)return!0;z.cursor++}return!1}return!0}function i(){if(z.in_grouping(y,97,250))for(;!z.out_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}return g=z.cursor,!0}function o(){var e,r,s=z.cursor;if(z.in_grouping(y,97,250))if(e=z.cursor,n()){if(z.cursor=e,i())return}else g=z.cursor;if(z.cursor=s,z.out_grouping(y,97,250)){if(r=z.cursor,n()){if(z.cursor=r,!z.in_grouping(y,97,250)||z.cursor>=z.limit)return;z.cursor++}g=z.cursor}}function t(){for(;!z.in_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}for(;!z.out_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}return!0}function a(){var e=z.cursor;g=z.limit,b=g,h=g,o(),z.cursor=e,t()&&(b=z.cursor,t()&&(h=z.cursor))}function u(){for(var e;;){if(z.bra=z.cursor,e=z.find_among(q,3))switch(z.ket=z.cursor,e){case 1:z.slice_from("ã");continue;case 2:z.slice_from("õ");continue;case 3:if(z.cursor>=z.limit)break;z.cursor++;continue}break}}function w(){return g<=z.cursor}function m(){return b<=z.cursor}function c(){return h<=z.cursor}function l(){var e;if(z.ket=z.cursor,!(e=z.find_among_b(F,45)))return!1;switch(z.bra=z.cursor,e){case 1:if(!c())return!1;z.slice_del();break;case 2:if(!c())return!1;z.slice_from("log");break;case 3:if(!c())return!1;z.slice_from("u");break;case 4:if(!c())return!1;z.slice_from("ente");break;case 5:if(!m())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(j,4),e&&(z.bra=z.cursor,c()&&(z.slice_del(),1==e&&(z.ket=z.cursor,z.eq_s_b(2,"at")&&(z.bra=z.cursor,c()&&z.slice_del()))));break;case 6:if(!c())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(C,3),e&&(z.bra=z.cursor,1==e&&c()&&z.slice_del());break;case 7:if(!c())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(P,3),e&&(z.bra=z.cursor,1==e&&c()&&z.slice_del());break;case 8:if(!c())return!1;z.slice_del(),z.ket=z.cursor,z.eq_s_b(2,"at")&&(z.bra=z.cursor,c()&&z.slice_del());break;case 9:if(!w()||!z.eq_s_b(1,"e"))return!1;z.slice_from("ir")}return!0}function f(){var e,r;if(z.cursor>=g){if(r=z.limit_backward,z.limit_backward=g,z.ket=z.cursor,e=z.find_among_b(S,120))return z.bra=z.cursor,1==e&&z.slice_del(),z.limit_backward=r,!0;z.limit_backward=r}return!1}function d(){var e;z.ket=z.cursor,(e=z.find_among_b(W,7))&&(z.bra=z.cursor,1==e&&w()&&z.slice_del())}function v(e,r){if(z.eq_s_b(1,e)){z.bra=z.cursor;var s=z.limit-z.cursor;if(z.eq_s_b(1,r))return z.cursor=z.limit-s,w()&&z.slice_del(),!1}return!0}function p(){var e;if(z.ket=z.cursor,e=z.find_among_b(L,4))switch(z.bra=z.cursor,e){case 1:w()&&(z.slice_del(),z.ket=z.cursor,z.limit-z.cursor,v("u","g")&&v("i","c"));break;case 2:z.slice_from("c")}}function _(){if(!l()&&(z.cursor=z.limit,!f()))return z.cursor=z.limit,void d();z.cursor=z.limit,z.ket=z.cursor,z.eq_s_b(1,"i")&&(z.bra=z.cursor,z.eq_s_b(1,"c")&&(z.cursor=z.limit,w()&&z.slice_del()))}var h,b,g,k=[new r("",-1,3),new r("ã",0,1),new r("õ",0,2)],q=[new r("",-1,3),new r("a~",0,1),new r("o~",0,2)],j=[new r("ic",-1,-1),new r("ad",-1,-1),new r("os",-1,-1),new r("iv",-1,1)],C=[new r("ante",-1,1),new r("avel",-1,1),new r("ível",-1,1)],P=[new r("ic",-1,1),new r("abil",-1,1),new r("iv",-1,1)],F=[new r("ica",-1,1),new r("ância",-1,1),new r("ência",-1,4),new r("ira",-1,9),new r("adora",-1,1),new r("osa",-1,1),new r("ista",-1,1),new r("iva",-1,8),new r("eza",-1,1),new r("logía",-1,2),new r("idade",-1,7),new r("ante",-1,1),new r("mente",-1,6),new r("amente",12,5),new r("ável",-1,1),new r("ível",-1,1),new r("ución",-1,3),new r("ico",-1,1),new r("ismo",-1,1),new r("oso",-1,1),new r("amento",-1,1),new r("imento",-1,1),new r("ivo",-1,8),new r("aça~o",-1,1),new r("ador",-1,1),new r("icas",-1,1),new r("ências",-1,4),new r("iras",-1,9),new r("adoras",-1,1),new r("osas",-1,1),new r("istas",-1,1),new r("ivas",-1,8),new r("ezas",-1,1),new r("logías",-1,2),new r("idades",-1,7),new r("uciones",-1,3),new r("adores",-1,1),new r("antes",-1,1),new r("aço~es",-1,1),new r("icos",-1,1),new r("ismos",-1,1),new r("osos",-1,1),new r("amentos",-1,1),new r("imentos",-1,1),new r("ivos",-1,8)],S=[new r("ada",-1,1),new r("ida",-1,1),new r("ia",-1,1),new r("aria",2,1),new r("eria",2,1),new r("iria",2,1),new r("ara",-1,1),new r("era",-1,1),new r("ira",-1,1),new r("ava",-1,1),new r("asse",-1,1),new r("esse",-1,1),new r("isse",-1,1),new r("aste",-1,1),new r("este",-1,1),new r("iste",-1,1),new r("ei",-1,1),new r("arei",16,1),new r("erei",16,1),new r("irei",16,1),new r("am",-1,1),new r("iam",20,1),new r("ariam",21,1),new r("eriam",21,1),new r("iriam",21,1),new r("aram",20,1),new r("eram",20,1),new r("iram",20,1),new r("avam",20,1),new r("em",-1,1),new r("arem",29,1),new r("erem",29,1),new r("irem",29,1),new r("assem",29,1),new r("essem",29,1),new r("issem",29,1),new r("ado",-1,1),new r("ido",-1,1),new r("ando",-1,1),new r("endo",-1,1),new r("indo",-1,1),new r("ara~o",-1,1),new r("era~o",-1,1),new r("ira~o",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("ir",-1,1),new r("as",-1,1),new r("adas",47,1),new r("idas",47,1),new r("ias",47,1),new r("arias",50,1),new r("erias",50,1),new r("irias",50,1),new r("aras",47,1),new r("eras",47,1),new r("iras",47,1),new r("avas",47,1),new r("es",-1,1),new r("ardes",58,1),new r("erdes",58,1),new r("irdes",58,1),new r("ares",58,1),new r("eres",58,1),new r("ires",58,1),new r("asses",58,1),new r("esses",58,1),new r("isses",58,1),new r("astes",58,1),new r("estes",58,1),new r("istes",58,1),new r("is",-1,1),new r("ais",71,1),new r("eis",71,1),new r("areis",73,1),new r("ereis",73,1),new r("ireis",73,1),new r("áreis",73,1),new r("éreis",73,1),new r("íreis",73,1),new r("ásseis",73,1),new r("ésseis",73,1),new r("ísseis",73,1),new r("áveis",73,1),new r("íeis",73,1),new r("aríeis",84,1),new r("eríeis",84,1),new r("iríeis",84,1),new r("ados",-1,1),new r("idos",-1,1),new r("amos",-1,1),new r("áramos",90,1),new r("éramos",90,1),new r("íramos",90,1),new r("ávamos",90,1),new r("íamos",90,1),new r("aríamos",95,1),new r("eríamos",95,1),new r("iríamos",95,1),new r("emos",-1,1),new r("aremos",99,1),new r("eremos",99,1),new r("iremos",99,1),new r("ássemos",99,1),new r("êssemos",99,1),new r("íssemos",99,1),new r("imos",-1,1),new r("armos",-1,1),new r("ermos",-1,1),new r("irmos",-1,1),new r("ámos",-1,1),new r("arás",-1,1),new r("erás",-1,1),new r("irás",-1,1),new r("eu",-1,1),new r("iu",-1,1),new r("ou",-1,1),new r("ará",-1,1),new r("erá",-1,1),new r("irá",-1,1)],W=[new r("a",-1,1),new r("i",-1,1),new r("o",-1,1),new r("os",-1,1),new r("á",-1,1),new r("í",-1,1),new r("ó",-1,1)],L=[new r("e",-1,1),new r("ç",-1,2),new r("é",-1,1),new r("ê",-1,1)],y=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,3,19,12,2],z=new s;this.setCurrent=function(e){z.setCurrent(e)},this.getCurrent=function(){return z.getCurrent()},this.stem=function(){var r=z.cursor;return e(),z.cursor=r,a(),z.limit_backward=r,z.cursor=z.limit,_(),z.cursor=z.limit,p(),z.cursor=z.limit_backward,u(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.pt.stemmer,"stemmer-pt"),e.pt.stopWordFilter=e.generateStopWordFilter("a ao aos aquela aquelas aquele aqueles aquilo as até com como da das de dela delas dele deles depois do dos e ela elas ele eles em entre era eram essa essas esse esses esta estamos estas estava estavam este esteja estejam estejamos estes esteve estive estivemos estiver estivera estiveram estiverem estivermos estivesse estivessem estivéramos estivéssemos estou está estávamos estão eu foi fomos for fora foram forem formos fosse fossem fui fôramos fôssemos haja hajam hajamos havemos hei houve houvemos houver houvera houveram houverei houverem houveremos houveria houveriam houvermos houverá houverão houveríamos houvesse houvessem houvéramos houvéssemos há hão isso isto já lhe lhes mais mas me mesmo meu meus minha minhas muito na nas nem no nos nossa nossas nosso nossos num numa não nós o os ou para pela pelas pelo pelos por qual quando que quem se seja sejam sejamos sem serei seremos seria seriam será serão seríamos seu seus somos sou sua suas são só também te tem temos tenha tenham tenhamos tenho terei teremos teria teriam terá terão teríamos teu teus teve tinha tinham tive tivemos tiver tivera tiveram tiverem tivermos tivesse tivessem tivéramos tivéssemos tu tua tuas tém tínhamos um uma você vocês vos à às éramos".split(" ")),e.Pipeline.registerFunction(e.pt.stopWordFilter,"stopWordFilter-pt")}}); -------------------------------------------------------------------------------- /docs/site/assets/javascripts/lunr/min/lunr.ru.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Russian` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n():n()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ru=function(){this.pipeline.reset(),this.pipeline.add(e.ru.trimmer,e.ru.stopWordFilter,e.ru.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ru.stemmer))},e.ru.wordCharacters="Ѐ-҄҇-ԯᴫᵸⷠ-ⷿꙀ-ꚟ︮︯",e.ru.trimmer=e.trimmerSupport.generateTrimmer(e.ru.wordCharacters),e.Pipeline.registerFunction(e.ru.trimmer,"trimmer-ru"),e.ru.stemmer=function(){var n=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,t=new function(){function e(){for(;!W.in_grouping(S,1072,1103);){if(W.cursor>=W.limit)return!1;W.cursor++}return!0}function t(){for(;!W.out_grouping(S,1072,1103);){if(W.cursor>=W.limit)return!1;W.cursor++}return!0}function w(){b=W.limit,_=b,e()&&(b=W.cursor,t()&&e()&&t()&&(_=W.cursor))}function i(){return _<=W.cursor}function u(e,n){var r,t;if(W.ket=W.cursor,r=W.find_among_b(e,n)){switch(W.bra=W.cursor,r){case 1:if(t=W.limit-W.cursor,!W.eq_s_b(1,"а")&&(W.cursor=W.limit-t,!W.eq_s_b(1,"я")))return!1;case 2:W.slice_del()}return!0}return!1}function o(){return u(h,9)}function s(e,n){var r;return W.ket=W.cursor,!!(r=W.find_among_b(e,n))&&(W.bra=W.cursor,1==r&&W.slice_del(),!0)}function c(){return s(g,26)}function m(){return!!c()&&(u(C,8),!0)}function f(){return s(k,2)}function l(){return u(P,46)}function a(){s(v,36)}function p(){var e;W.ket=W.cursor,(e=W.find_among_b(F,2))&&(W.bra=W.cursor,i()&&1==e&&W.slice_del())}function d(){var e;if(W.ket=W.cursor,e=W.find_among_b(q,4))switch(W.bra=W.cursor,e){case 1:if(W.slice_del(),W.ket=W.cursor,!W.eq_s_b(1,"н"))break;W.bra=W.cursor;case 2:if(!W.eq_s_b(1,"н"))break;case 3:W.slice_del()}}var _,b,h=[new n("в",-1,1),new n("ив",0,2),new n("ыв",0,2),new n("вши",-1,1),new n("ивши",3,2),new n("ывши",3,2),new n("вшись",-1,1),new n("ившись",6,2),new n("ывшись",6,2)],g=[new n("ее",-1,1),new n("ие",-1,1),new n("ое",-1,1),new n("ые",-1,1),new n("ими",-1,1),new n("ыми",-1,1),new n("ей",-1,1),new n("ий",-1,1),new n("ой",-1,1),new n("ый",-1,1),new n("ем",-1,1),new n("им",-1,1),new n("ом",-1,1),new n("ым",-1,1),new n("его",-1,1),new n("ого",-1,1),new n("ему",-1,1),new n("ому",-1,1),new n("их",-1,1),new n("ых",-1,1),new n("ею",-1,1),new n("ою",-1,1),new n("ую",-1,1),new n("юю",-1,1),new n("ая",-1,1),new n("яя",-1,1)],C=[new n("ем",-1,1),new n("нн",-1,1),new n("вш",-1,1),new n("ивш",2,2),new n("ывш",2,2),new n("щ",-1,1),new n("ющ",5,1),new n("ующ",6,2)],k=[new n("сь",-1,1),new n("ся",-1,1)],P=[new n("ла",-1,1),new n("ила",0,2),new n("ыла",0,2),new n("на",-1,1),new n("ена",3,2),new n("ете",-1,1),new n("ите",-1,2),new n("йте",-1,1),new n("ейте",7,2),new n("уйте",7,2),new n("ли",-1,1),new n("или",10,2),new n("ыли",10,2),new n("й",-1,1),new n("ей",13,2),new n("уй",13,2),new n("л",-1,1),new n("ил",16,2),new n("ыл",16,2),new n("ем",-1,1),new n("им",-1,2),new n("ым",-1,2),new n("н",-1,1),new n("ен",22,2),new n("ло",-1,1),new n("ило",24,2),new n("ыло",24,2),new n("но",-1,1),new n("ено",27,2),new n("нно",27,1),new n("ет",-1,1),new n("ует",30,2),new n("ит",-1,2),new n("ыт",-1,2),new n("ют",-1,1),new n("уют",34,2),new n("ят",-1,2),new n("ны",-1,1),new n("ены",37,2),new n("ть",-1,1),new n("ить",39,2),new n("ыть",39,2),new n("ешь",-1,1),new n("ишь",-1,2),new n("ю",-1,2),new n("ую",44,2)],v=[new n("а",-1,1),new n("ев",-1,1),new n("ов",-1,1),new n("е",-1,1),new n("ие",3,1),new n("ье",3,1),new n("и",-1,1),new n("еи",6,1),new n("ии",6,1),new n("ами",6,1),new n("ями",6,1),new n("иями",10,1),new n("й",-1,1),new n("ей",12,1),new n("ией",13,1),new n("ий",12,1),new n("ой",12,1),new n("ам",-1,1),new n("ем",-1,1),new n("ием",18,1),new n("ом",-1,1),new n("ям",-1,1),new n("иям",21,1),new n("о",-1,1),new n("у",-1,1),new n("ах",-1,1),new n("ях",-1,1),new n("иях",26,1),new n("ы",-1,1),new n("ь",-1,1),new n("ю",-1,1),new n("ию",30,1),new n("ью",30,1),new n("я",-1,1),new n("ия",33,1),new n("ья",33,1)],F=[new n("ост",-1,1),new n("ость",-1,1)],q=[new n("ейше",-1,1),new n("н",-1,2),new n("ейш",-1,1),new n("ь",-1,3)],S=[33,65,8,232],W=new r;this.setCurrent=function(e){W.setCurrent(e)},this.getCurrent=function(){return W.getCurrent()},this.stem=function(){return w(),W.cursor=W.limit,!(W.cursor=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor++,!0}return!1},in_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e<=s&&e>=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor--,!0}return!1},out_grouping:function(t,i,s){if(this.cursors||e>3]&1<<(7&e)))return this.cursor++,!0}return!1},out_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e>s||e>3]&1<<(7&e)))return this.cursor--,!0}return!1},eq_s:function(t,i){if(this.limit-this.cursor>1),f=0,l=o0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n+_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n+_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},find_among_b:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit_backward,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o=0;m--){if(n-l==u){f=-1;break}if(f=r.charCodeAt(n-1-l)-_.s[m])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n-_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n-_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},replace_s:function(t,i,s){var e=s.length-(i-t),n=r.substring(0,t),u=r.substring(i);return r=n+s+u,this.limit+=e,this.cursor>=i?this.cursor+=e:this.cursor>t&&(this.cursor=t),e},slice_check:function(){if(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>r.length)throw"faulty slice operation"},slice_from:function(r){this.slice_check(),this.replace_s(this.bra,this.ket,r)},slice_del:function(){this.slice_from("")},insert:function(r,t,i){var s=this.replace_s(r,t,i);r<=this.bra&&(this.bra+=s),r<=this.ket&&(this.ket+=s)},slice_to:function(){return this.slice_check(),r.substring(this.bra,this.ket)},eq_v_b:function(r){return this.eq_s_b(r.length,r)}}}},r.trimmerSupport={generateTrimmer:function(r){var t=new RegExp("^[^"+r+"]+"),i=new RegExp("[^"+r+"]+$");return function(r){return"function"==typeof r.update?r.update(function(r){return r.replace(t,"").replace(i,"")}):r.replace(t,"").replace(i,"")}}}}}); -------------------------------------------------------------------------------- /docs/site/assets/javascripts/lunr/min/lunr.sv.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Swedish` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,t=new function(){function e(){var e,r=w.cursor+3;if(o=w.limit,0<=r||r<=w.limit){for(a=r;;){if(e=w.cursor,w.in_grouping(l,97,246)){w.cursor=e;break}if(w.cursor=e,w.cursor>=w.limit)return;w.cursor++}for(;!w.out_grouping(l,97,246);){if(w.cursor>=w.limit)return;w.cursor++}o=w.cursor,o=o&&(w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(u,37),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.in_grouping_b(d,98,121)&&w.slice_del()}}function i(){var e=w.limit_backward;w.cursor>=o&&(w.limit_backward=o,w.cursor=w.limit,w.find_among_b(c,7)&&(w.cursor=w.limit,w.ket=w.cursor,w.cursor>w.limit_backward&&(w.bra=--w.cursor,w.slice_del())),w.limit_backward=e)}function s(){var e,r;if(w.cursor>=o){if(r=w.limit_backward,w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(m,5))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.slice_from("lös");break;case 3:w.slice_from("full")}w.limit_backward=r}}var a,o,u=[new r("a",-1,1),new r("arna",0,1),new r("erna",0,1),new r("heterna",2,1),new r("orna",0,1),new r("ad",-1,1),new r("e",-1,1),new r("ade",6,1),new r("ande",6,1),new r("arne",6,1),new r("are",6,1),new r("aste",6,1),new r("en",-1,1),new r("anden",12,1),new r("aren",12,1),new r("heten",12,1),new r("ern",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",18,1),new r("or",-1,1),new r("s",-1,2),new r("as",21,1),new r("arnas",22,1),new r("ernas",22,1),new r("ornas",22,1),new r("es",21,1),new r("ades",26,1),new r("andes",26,1),new r("ens",21,1),new r("arens",29,1),new r("hetens",29,1),new r("erns",21,1),new r("at",-1,1),new r("andet",-1,1),new r("het",-1,1),new r("ast",-1,1)],c=[new r("dd",-1,-1),new r("gd",-1,-1),new r("nn",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1),new r("tt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("els",-1,1),new r("fullt",-1,3),new r("löst",-1,2)],l=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],d=[119,127,149],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,t(),w.cursor=w.limit,i(),w.cursor=w.limit,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return t.setCurrent(e),t.stem(),t.getCurrent()}):(t.setCurrent(e),t.stem(),t.getCurrent())}}(),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}}); -------------------------------------------------------------------------------- /docs/site/assets/javascripts/lunr/min/lunr.vi.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.vi=function(){this.pipeline.reset(),this.pipeline.add(e.vi.stopWordFilter,e.vi.trimmer)},e.vi.wordCharacters="[A-Za-ẓ̀͐́͑̉̃̓ÂâÊêÔôĂ-ăĐ-đƠ-ơƯ-ư]",e.vi.trimmer=e.trimmerSupport.generateTrimmer(e.vi.wordCharacters),e.Pipeline.registerFunction(e.vi.trimmer,"trimmer-vi"),e.vi.stopWordFilter=e.generateStopWordFilter("là cái nhưng mà".split(" "))}}); -------------------------------------------------------------------------------- /docs/site/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | None 4 | 2020-10-18 5 | daily 6 | 7 | None 8 | 2020-10-18 9 | daily 10 | 11 | None 12 | 2020-10-18 13 | daily 14 | 15 | None 16 | 2020-10-18 17 | daily 18 | 19 | None 20 | 2020-10-18 21 | daily 22 | 23 | None 24 | 2020-10-18 25 | daily 26 | 27 | None 28 | 2020-10-18 29 | daily 30 | 31 | None 32 | 2020-10-18 33 | daily 34 | 35 | None 36 | 2020-10-18 37 | daily 38 | 39 | None 40 | 2020-10-18 41 | daily 42 | 43 | None 44 | 2020-10-18 45 | daily 46 | 47 | -------------------------------------------------------------------------------- /docs/site/sitemap.xml.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeBardian/tplink-smartdevices-netstandard/2566af2a3a184e9746934af5668c5ab9a8735b88/docs/site/sitemap.xml.gz -------------------------------------------------------------------------------- /tplink-smartdevices/Data/BoolConverter.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace TPLinkSmartDevices.Data 7 | { 8 | internal class BoolConverter : JsonConverter 9 | { 10 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 11 | { 12 | writer.WriteValue(((bool)value) ? 1 : 0); 13 | } 14 | 15 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 16 | { 17 | return reader.Value.ToString() == "1"; 18 | } 19 | 20 | public override bool CanConvert(Type objectType) 21 | { 22 | return objectType == typeof(bool); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tplink-smartdevices/Data/BulbHSV.cs: -------------------------------------------------------------------------------- 1 | namespace TPLinkSmartDevices.Data 2 | { 3 | public class BulbHSV 4 | { 5 | public int Hue { get; set; } 6 | public int Saturation { get; set; } 7 | public int Value { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tplink-smartdevices/Data/CountDownRule/CountDownRule.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Linq; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using TPLinkSmartDevices.Devices; 9 | 10 | namespace TPLinkSmartDevices.Data.CountDownRule 11 | { 12 | public class CountDownRule 13 | { 14 | /// 15 | /// identifier of CountDown rule 16 | /// 17 | [JsonProperty("id")] 18 | public string Id { get; internal set; } 19 | 20 | /// 21 | /// custom name of CountDown rule 22 | /// 23 | [JsonProperty("name")] 24 | public string Name { get; set; } 25 | 26 | /// 27 | /// if the rule is currently active or not 28 | /// 29 | [JsonProperty("enable")] 30 | [JsonConverter(typeof(BoolConverter))] 31 | public bool Enabled { get; set; } 32 | 33 | /// 34 | /// if the device should be powered on or off after the timer runs out 35 | /// 36 | [JsonProperty("act")] 37 | [JsonConverter(typeof(BoolConverter))] 38 | public bool PoweredOn { get; set; } 39 | 40 | /// 41 | /// delay in seconds after which the action triggers 42 | /// 43 | [JsonProperty("delay")] 44 | public int Delay { get; set; } 45 | 46 | public bool ShouldSerializeId() 47 | { 48 | return Id != null; 49 | } 50 | } 51 | 52 | internal static class CountDownExtensions 53 | { 54 | internal static async Task> RetrieveCountDownRules(this ICountDown device, string ns) 55 | { 56 | dynamic result = await ((TPLinkSmartDevice)device).Execute(ns, "get_rules").ConfigureAwait(false); 57 | string rule_list = Convert.ToString(result.rule_list); 58 | return JsonConvert.DeserializeObject>(rule_list); 59 | } 60 | 61 | internal static async Task AddCountDownRule(this ICountDown device, string ns, CountDownRule cdr) 62 | { 63 | JObject payload = JObject.FromObject(cdr); 64 | dynamic result = await ((TPLinkSmartDevice)device).Execute(ns, "add_rule", payload).ConfigureAwait(false); 65 | cdr.Id = (string)result.id; 66 | return cdr; 67 | } 68 | 69 | internal static async Task EditCountDownRule(this ICountDown device, string ns, CountDownRule cdr) 70 | { 71 | JObject payload = JObject.FromObject(cdr); 72 | dynamic result = await ((TPLinkSmartDevice)device).Execute(ns, "edit_rule", payload).ConfigureAwait(false); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tplink-smartdevices/Data/CountDownRule/ICountDown.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | using TPLinkSmartDevices.Data.CountDownRule; 6 | 7 | namespace TPLinkSmartDevices.Devices 8 | { 9 | interface ICountDown 10 | { 11 | List CountDownRules { get; } 12 | Task RetrieveCountDownRules(); 13 | Task AddCountDownRule(CountDownRule cdr); 14 | Task EditCountDownRule(string id, bool? enabled = null, int? delay = null, bool? poweredOn = null, string name = null); 15 | Task EditCountDownRule(CountDownRule cdr); 16 | Task DeleteCountDownRule(string id); 17 | Task DeleteAllCountDownRules(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tplink-smartdevices/Data/DimmerOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TPLinkSmartDevices.Devices 4 | { 5 | public class DimmerOptions 6 | { 7 | public DimmerOptions() 8 | { 9 | FadeOnTime = 2000; 10 | FadeOffTime = 2000; 11 | GentleOnTime = 2000; 12 | GentleOffTime = 2000; 13 | DoubleClickAction = DimmerMode.GentleOnOff; 14 | LongPressAction = DimmerMode.GentleOnOff; 15 | Mode = DimmerMode.GentleOnOff; 16 | } 17 | 18 | public int FadeOnTime { get; set; } 19 | public int FadeOffTime { get; set; } 20 | public int GentleOnTime { get; set; } 21 | public int GentleOffTime { get; set; } 22 | 23 | public DimmerMode DoubleClickAction { get; set; } 24 | public DimmerMode LongPressAction { get; set; } 25 | public DimmerMode Mode { get; set; } 26 | } 27 | 28 | public enum DimmerMode 29 | { 30 | GentleOnOff, 31 | InstantOnOff, 32 | Preset, 33 | None 34 | } 35 | 36 | public static class DimmerModeExtensions 37 | { 38 | public static string ToStr(this DimmerMode mode) 39 | { 40 | return mode switch 41 | { 42 | DimmerMode.None => "none", 43 | DimmerMode.GentleOnOff => "gentle_on_off", 44 | DimmerMode.InstantOnOff => "instant_on_off", 45 | DimmerMode.Preset => "customize_preset", 46 | _ => "", 47 | }; 48 | } 49 | 50 | public static DimmerMode ToDimmerMode(this string str) 51 | { 52 | return str switch 53 | { 54 | "none" => DimmerMode.None, 55 | "gentle_on_off" => DimmerMode.GentleOnOff, 56 | "instant_on_off" => DimmerMode.InstantOnOff, 57 | "customize_preset" => DimmerMode.Preset, 58 | _ => throw new ArgumentException($"can't parse {str} to DimmerMode"), 59 | }; 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /tplink-smartdevices/Data/LightDetails.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace TPLinkSmartDevices.Data 7 | { 8 | public class LightDetails 9 | { 10 | [JsonProperty("lamp_beam_angle")] 11 | public int LampBeamAngle { get; set; } 12 | 13 | [JsonProperty("min_voltage")] 14 | public int MinVoltage { get; set; } 15 | 16 | [JsonProperty("max_voltage")] 17 | public int MaxVoltage { get; set; } 18 | 19 | [JsonProperty("max_lumens")] 20 | public int MaxLumens { get; set; } 21 | 22 | [JsonProperty("wattage")] 23 | public int Wattage { get; set; } 24 | 25 | [JsonProperty("incandescent_equivalent")] 26 | public int IncandescentEquivalent { get; set; } 27 | 28 | [JsonProperty("color_rendering_index")] 29 | public int ColorRenderingIndex { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tplink-smartdevices/Data/PowerData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace TPLinkSmartDevices.Data 8 | { 9 | /// 10 | /// Encapsulates JSON data structure for current energy use as metered by the HS110 Smart Energy Meter. 11 | /// 12 | public class PowerData 13 | { 14 | private readonly dynamic _powerData; 15 | private string _hwversion; 16 | 17 | public PowerData(dynamic powerData, string hwversion) 18 | { 19 | _powerData = powerData; 20 | _hwversion = hwversion; 21 | } 22 | 23 | /// 24 | /// Currently measured voltage in volts. 25 | /// 26 | public double Voltage => _hwversion.StartsWith("1") ? _powerData.voltage : _powerData.voltage_mv / 1000.0d; 27 | 28 | /// 29 | /// Currently measured current in amperes. 30 | /// 31 | public double Amperage => _hwversion.StartsWith("1") ? _powerData.current : _powerData.current_ma / 1000.0d; 32 | 33 | /// 34 | /// Currently measured power in watts. 35 | /// 36 | public double Power => _hwversion.StartsWith("1") ? _powerData.power : _powerData.power_mw / 1000.0d; 37 | 38 | /// 39 | /// Total power consumption in kilowatthours. 40 | /// 41 | public double Total => _hwversion.StartsWith("1") ? _powerData.total : _powerData.total_wh / 1000.0d; 42 | 43 | public int ErrorCode => _powerData.err_code; 44 | 45 | public override string ToString() 46 | { 47 | return $"{Voltage:0.00} Volt, {Amperage:0.00} Ampere, {Power:0.00} Watt"; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tplink-smartdevices/Data/Schedule/ISchedule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace TPLinkSmartDevices.Data.Schedule 7 | { 8 | interface ISchedule 9 | { 10 | List Schedules { get; } 11 | Task RetrieveSchedules(); 12 | Task AddSchedule(Schedule schedule); 13 | Task EditSchedule(Schedule schedule); 14 | Task DeleteSchedule(string id); 15 | Task DeleteSchedules(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tplink-smartdevices/Data/Schedule/Schedule.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Linq; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Runtime.Serialization; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using TPLinkSmartDevices.Devices; 9 | 10 | namespace TPLinkSmartDevices.Data.Schedule 11 | { 12 | public class Schedule 13 | { 14 | /// 15 | /// identifier of schedule 16 | /// 17 | [JsonProperty("id")] 18 | public string Id { get; set; } 19 | 20 | /// 21 | /// custom name of CountDown rule 22 | /// 23 | [JsonProperty("name")] 24 | public string Name { get; set; } 25 | 26 | /// 27 | /// start time option for schedule 28 | /// 29 | [JsonProperty("stime_opt")] 30 | public TimeOption StartTimeOption { get; set; } 31 | 32 | /// 33 | /// start time after midnight 34 | /// 35 | [JsonProperty("smin")] 36 | [JsonConverter(typeof(TimeSpanConverter))] 37 | public TimeSpan StartTime { get; set; } 38 | 39 | /// 40 | /// whether to turn device on or off at start of rule. 41 | /// 0 = turn off, 42 | /// 1 = turn on, 43 | /// -1 and 2: purpose still unknown 44 | /// 45 | [JsonProperty("sact")] 46 | public int StartAction { get; set; } 47 | 48 | /// 49 | /// end time option for schedule 50 | /// 51 | [JsonProperty("etime_opt")] 52 | public TimeOption EndTimeOption { get; set; } 53 | 54 | /// 55 | /// end time in minutes after midnight 56 | /// 57 | [JsonProperty("emin")] 58 | [JsonConverter(typeof(TimeSpanConverter))] 59 | public TimeSpan EndTime { get; set; } 60 | 61 | /// 62 | /// whether to turn device on or off at end of rule. 63 | /// 0 = turn off, 64 | /// 1 = turn on, 65 | /// -1 and 2: purpose still unknown 66 | /// 67 | [JsonProperty("eact")] 68 | public int EndAction { get; set; } 69 | 70 | /// 71 | /// days that rule should be active, 72 | /// 73 | [JsonProperty("wday")] 74 | [JsonConverter(typeof(WeekdayConverter))] 75 | public Weekdays Weekdays { get; set; } 76 | 77 | /// 78 | /// if the schdeule is currently active or not 79 | /// 80 | [JsonProperty("enable")] 81 | [JsonConverter(typeof(BoolConverter))] 82 | public bool Enabled { get; set; } 83 | 84 | /// 85 | /// whether the rule will be used more than one time. 86 | /// 87 | [JsonProperty("repeat")] 88 | [JsonConverter(typeof(BoolConverter))] 89 | //seems to be required to set to true, otherwise throws -3 protocol error 90 | public bool Repeat => true; 91 | 92 | [JsonProperty("s_light")] 93 | public object LightState => new { saturation = Saturation, hue = Hue, brightness = Brightness, color_temp = ColorTemp }; 94 | 95 | /// 96 | /// sets saturation of bulb’s light output. values from 0 to 100 are accepted. 97 | /// 98 | [JsonIgnore] 99 | public int Saturation { get; set; } 100 | 101 | /// 102 | /// sets hue of bulb’s light output. values from 0 to 360 accepted. 103 | /// 104 | [JsonIgnore] 105 | public int Hue { get; set; } 106 | 107 | /// 108 | /// sets brightness of bulb’s light output. values from 0 to 100 are accepted. 109 | /// 110 | [JsonIgnore] 111 | public int Brightness { get; set; } 112 | 113 | /// 114 | /// sets brightness of bulb’s light output. values from 0 to 100 are accepted. 115 | /// 116 | [JsonIgnore] 117 | public int ColorTemp { get; set; } 118 | 119 | [JsonExtensionData] 120 | private IDictionary _additionalData = new Dictionary(); 121 | 122 | [OnDeserialized] 123 | private void OnDeserialized(StreamingContext context) 124 | { 125 | if (_additionalData.ContainsKey("s_light")) 126 | { 127 | Hue = (int)_additionalData["s_light"]["hue"]; 128 | Saturation = (int)_additionalData["s_light"]["saturation"]; 129 | Brightness = (int)_additionalData["s_light"]["brightness"]; 130 | ColorTemp = (int)_additionalData["s_light"]["color_temp"]; 131 | } 132 | } 133 | 134 | public bool ShouldSerializeId() 135 | { 136 | return Id != null; 137 | } 138 | 139 | //TODO: additional unknown parameters: latitude, longitude, year, month, day, force, frequency, on_off, eoffset/soffset !! 140 | } 141 | 142 | internal class TimeSpanConverter : JsonConverter 143 | { 144 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 145 | { 146 | int timeSinceMidnight = Convert.ToInt32(((TimeSpan)value).TotalMinutes); 147 | if (timeSinceMidnight > 1440) throw new ArgumentException("invalid time span"); 148 | writer.WriteValue(timeSinceMidnight); 149 | } 150 | 151 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 152 | { 153 | return TimeSpan.FromMinutes(Convert.ToDouble(reader.Value)); 154 | } 155 | 156 | public override bool CanConvert(Type objectType) 157 | { 158 | return objectType == typeof(TimeSpan); 159 | } 160 | } 161 | 162 | internal static class SchedulesExtensions 163 | { 164 | internal static async Task> RetrieveSchedules(this ISchedule device, string ns) 165 | { 166 | dynamic result = await ((TPLinkSmartDevice)device).Execute(ns, "get_rules").ConfigureAwait(false); 167 | string rule_list = Convert.ToString(result.rule_list); 168 | return JsonConvert.DeserializeObject>(rule_list); 169 | } 170 | 171 | internal static async Task AddSchedule(this ISchedule device, string ns, Schedule schedule) 172 | { 173 | JObject payload = JObject.FromObject(schedule); 174 | if (ns == "schedule") 175 | { 176 | payload.Property("s_light")?.Remove(); 177 | } 178 | dynamic result = await ((TPLinkSmartDevice)device).Execute(ns, "add_rule", payload).ConfigureAwait(false); 179 | schedule.Id = (string)result.id; 180 | device.Schedules.Add(schedule); 181 | } 182 | 183 | internal static async Task EditSchedule(this ISchedule device, string ns, Schedule schedule) 184 | { 185 | JObject payload = JObject.FromObject(schedule); 186 | dynamic result = await ((TPLinkSmartDevice)device).Execute(ns, "edit_rule", payload).ConfigureAwait(false); 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /tplink-smartdevices/Data/Schedule/TimeOption.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace TPLinkSmartDevices.Data.Schedule 6 | { 7 | public enum TimeOption 8 | { 9 | None = -1, 10 | Custom = 0, 11 | Sunrise = 1, 12 | Sunset = 2 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tplink-smartdevices/Data/Schedule/Weekdays.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Linq; 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace TPLinkSmartDevices.Data.Schedule 10 | { 11 | [Flags] 12 | public enum Weekdays 13 | { 14 | None = 0, 15 | Sunday = 1 << 0, 16 | Monday = 1 << 1, 17 | Tuesday = 1 << 2, 18 | Wednesday = 1 << 3, 19 | Thursday = 1 << 4, 20 | Friday = 1 << 5, 21 | Saturday = 1 << 6, 22 | WeekendDays = Sunday | Saturday, 23 | WorkDays = Monday | Tuesday | Wednesday | Thursday | Friday, 24 | EveryDay = WeekendDays | WorkDays 25 | } 26 | 27 | /// 28 | /// converts Weekdays flags to array of weekday bits. example: (Weekdays.Saturday | Weekdays.Monday) ==> [0, 1, 0, 0, 0, 0, 1] 29 | /// 30 | public class WeekdayConverter : JsonConverter 31 | { 32 | 33 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 34 | { 35 | Weekdays weekdays = (Weekdays)value; 36 | 37 | writer.WriteStartArray(); 38 | for (int i = 0; i < 7; i++) 39 | { 40 | if (weekdays.HasFlag((Weekdays)(1 << i))) 41 | { 42 | writer.WriteValue(1); 43 | } 44 | else 45 | { 46 | writer.WriteValue(0); 47 | } 48 | } 49 | writer.WriteEndArray(); 50 | } 51 | 52 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 53 | { 54 | Weekdays weekdays = Weekdays.None; 55 | if (reader.TokenType != JsonToken.StartArray) 56 | { 57 | return weekdays; 58 | } 59 | JArray daySource = JArray.Load(reader); 60 | for (int i = 0; i < daySource.Count; i++) 61 | { 62 | if ((int)daySource[i] == 0) continue; 63 | 64 | weekdays |= (Weekdays)(1 << i); 65 | } 66 | 67 | return weekdays; 68 | } 69 | 70 | public override bool CanWrite => true; 71 | 72 | public override bool CanConvert(Type objectType) 73 | { 74 | return false; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tplink-smartdevices/Devices/TPLinkSmartDevice.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using System; 3 | using System.Threading.Tasks; 4 | using TPLinkSmartDevices.Messaging; 5 | 6 | namespace TPLinkSmartDevices.Devices 7 | { 8 | public abstract class TPLinkSmartDevice 9 | { 10 | const byte INITIALIZATION_VECTOR = 171; 11 | 12 | public string Hostname { get; protected set; } 13 | public int Port { get; protected set; } 14 | 15 | public IMessageCache MessageCache { get; set; } = new TimeGatedMessageCache(2); 16 | 17 | public string SoftwareVersion { get; private set; } 18 | public string HardwareVersion { get; private set; } 19 | public string Type { get; private set; } 20 | public string Model { get; private set; } 21 | public string MacAddress { get; private set; } 22 | public string DevName { get; private set; } 23 | public string HardwareId { get; private set; } 24 | public string FirmwareId { get; private set; } 25 | public string DeviceId { get; private set; } 26 | public string OemId { get; private set; } 27 | public string CloudServer { get; private set; } 28 | public bool RemoteAccessEnabled { get; set; } 29 | public int RSSI { get; private set; } 30 | public double[] LocationLatLong { get; private set; } 31 | 32 | public string Alias { get; private set; } 33 | 34 | private DateTime CurrentTime {get; set; } 35 | 36 | protected TPLinkSmartDevice(string hostname, int port=9999) 37 | { 38 | Hostname = hostname; 39 | Port = port; 40 | } 41 | 42 | protected TPLinkSmartDevice() { } 43 | 44 | /// 45 | /// Refresh device information 46 | /// 47 | public async Task Refresh(dynamic sysInfo = null) 48 | { 49 | await GetCloudInfo().ConfigureAwait(false); 50 | if (sysInfo == null) 51 | sysInfo = await Execute("system", "get_sysinfo").ConfigureAwait(false); 52 | 53 | SoftwareVersion = sysInfo.sw_ver; 54 | HardwareVersion = sysInfo.hw_ver; 55 | Type = sysInfo.type; 56 | Model = sysInfo.model; 57 | MacAddress = sysInfo.mac; 58 | DevName = sysInfo.dev_name; 59 | Alias = sysInfo.alias; 60 | HardwareId = sysInfo.hwId; 61 | FirmwareId = sysInfo.fwId; 62 | DeviceId = sysInfo.deviceId; 63 | OemId = sysInfo.oemId; 64 | RSSI = sysInfo.rssi; 65 | 66 | if (sysInfo.latitude != null) 67 | LocationLatLong = new double[2] { sysInfo.latitude, sysInfo.longitude }; 68 | else if (sysInfo.latitude_i != null) 69 | LocationLatLong = new double[2] { sysInfo.latitude_i, sysInfo.longitude_i }; 70 | } 71 | 72 | /// 73 | /// Sends command to device and returns answer 74 | /// 75 | protected internal async Task Execute(string system, string command, object argument = null, object value = null) 76 | { 77 | var message = new SmartHomeProtocolMessage(system, command, argument, value); 78 | return await MessageCache.Request(message, Hostname, Port).ConfigureAwait(false); 79 | } 80 | 81 | protected internal async Task Execute(string system, string command, string json) 82 | { 83 | var message = new SmartHomeProtocolMessage(system, command, json); 84 | return await MessageCache.Request(message, Hostname, Port); 85 | } 86 | 87 | public async Task SetAlias(string value) 88 | { 89 | await Execute("system", "set_dev_alias", "alias", value).ConfigureAwait(false); 90 | this.Alias = value; 91 | } 92 | 93 | public async Task GetTime() 94 | { 95 | dynamic rawTime = await Execute("time", "get_time").ConfigureAwait(false); 96 | return new DateTime((int)rawTime.year, (int)rawTime.month, (int)rawTime.mday, (int)rawTime.hour, (int)rawTime.min, (int)rawTime.sec); 97 | } 98 | 99 | public async Task GetCloudInfo() 100 | { 101 | dynamic cloudInfo = await Execute("cnCloud", "get_info").ConfigureAwait(false); 102 | if (cloudInfo == null) 103 | { 104 | RemoteAccessEnabled = false; 105 | return; 106 | } 107 | CloudServer = (string)cloudInfo.server; 108 | RemoteAccessEnabled = Convert.ToBoolean((int)cloudInfo.binded); 109 | } 110 | 111 | /// 112 | /// Binds account to cloud server 113 | /// 114 | public async Task ConfigureRemoteAccess(string username, string password) 115 | { 116 | if (!RemoteAccessEnabled) await SetRemoteAccessEnabled(true).ConfigureAwait(false); 117 | try 118 | { 119 | dynamic result = await Execute("cnCloud", "bind", new JObject 120 | { 121 | new JProperty("username", username), 122 | new JProperty("password", password) 123 | }, null).ConfigureAwait(false); 124 | } 125 | catch (Exception e) 126 | { 127 | RemoteAccessEnabled = false; 128 | if (e.Message.Contains("20601") || e.Message.Contains("3")) 129 | { 130 | throw new Exception("The specified password is incorrect"); 131 | } 132 | else if (e.Message.Contains("20600")) 133 | { 134 | throw new Exception("The username wasn't found"); 135 | }; 136 | throw new Exception("Internal error"); 137 | } 138 | } 139 | 140 | /// 141 | /// Unbinds currently set account from cloud server 142 | /// 143 | public async Task UnbindRemoteAccess() 144 | { 145 | dynamic result = await Execute("cnCloud", "unbind").ConfigureAwait(false); 146 | await SetRemoteAccessEnabled(false).ConfigureAwait(false); 147 | } 148 | 149 | private async Task SetRemoteAccessEnabled(bool enabled, string server = "n-devs.tplinkcloud.com") 150 | { 151 | if (enabled) 152 | { 153 | dynamic result = await Execute("cnCloud", "set_server_url", "server", server).ConfigureAwait(false); 154 | RemoteAccessEnabled = true; 155 | } 156 | else 157 | { 158 | dynamic result = await Execute("cnCloud", "set_server_url", "server", "bogus.server.com").ConfigureAwait(false); 159 | RemoteAccessEnabled = false; 160 | } 161 | } 162 | 163 | public abstract Task SetPoweredOn(bool value); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /tplink-smartdevices/Devices/TPLinkSmartDimmer.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace TPLinkSmartDevices.Devices 9 | { 10 | public partial class TPLinkSmartDimmer : TPLinkSmartPlug 11 | { 12 | private DimmerOptions _options; 13 | private bool _poweredOn; 14 | private int _brightness; 15 | private int[] _presets; 16 | 17 | public bool PoweredOn => _poweredOn; 18 | public int Brightness => _brightness; 19 | public int[] Presets => _presets; 20 | public DimmerOptions Options => _options; 21 | 22 | [Obsolete("Use async factory method TPLinkSmartDimmer.Create() instead")] 23 | public TPLinkSmartDimmer(string hostName, int port = 9999, DimmerOptions opts = null) : base(hostName, port) 24 | { 25 | Task.Run(async () => 26 | { 27 | this._options = opts ?? new DimmerOptions(); 28 | await Refresh().ConfigureAwait(false); 29 | }).GetAwaiter().GetResult(); 30 | } 31 | 32 | private TPLinkSmartDimmer() { } 33 | 34 | public static async Task Create(string hostname, int port = 9999, DimmerOptions opts = null) 35 | { 36 | var d = new TPLinkSmartDimmer() { Hostname = hostname, Port = port }; 37 | d._options = opts ?? new DimmerOptions(); 38 | await d.Refresh().ConfigureAwait(false); 39 | return d; 40 | } 41 | 42 | public new async Task Refresh() 43 | { 44 | dynamic sysInfo = await Execute("system", "get_sysinfo").ConfigureAwait(false); 45 | _poweredOn = (int)sysInfo.relay_state == 1; 46 | _brightness = (int)sysInfo.brightness; 47 | 48 | dynamic defaultBehavior = await Execute("smartlife.iot.dimmer", "get_default_behavior").ConfigureAwait(false); 49 | string long_press = (string)defaultBehavior.long_press.mode; 50 | string double_click = (string)defaultBehavior.double_click.mode; 51 | _options.LongPressAction = long_press.ToDimmerMode(); 52 | _options.DoubleClickAction = double_click.ToDimmerMode(); 53 | 54 | RetrievePresets(sysInfo); 55 | await Refresh((object)sysInfo).ConfigureAwait(false); 56 | } 57 | 58 | private void RetrievePresets(dynamic sysinfo) 59 | { 60 | JArray presets = JArray.Parse(Convert.ToString(sysinfo.preferred_state)); 61 | _presets = presets.Select(x => (int)x["brightness"]).ToArray(); 62 | } 63 | 64 | /// 65 | /// Set power state of dimming switch 66 | /// 67 | public override async Task SetPoweredOn(bool value) 68 | { 69 | await Execute("smartlife.iot.dimmer", "set_switch_state", "state", value ? 1 : 0).ConfigureAwait(false); 70 | _poweredOn = value; 71 | } 72 | 73 | /// 74 | /// Transition to a specified brightness level 75 | /// 76 | public async Task TransitionBrightness(int brightness, DimmerMode? mode = null, int? duration = null) 77 | { 78 | if (brightness < 0 || brightness > 100) throw new ArgumentException("brightness should be between 0 and 100"); 79 | 80 | await Execute("smartlife.iot.dimmer", "set_dimmer_transition", new JObject 81 | { 82 | new JProperty("brightness", brightness), 83 | new JProperty("mode", (mode ?? _options.Mode).ToStr()), 84 | new JProperty("duration", duration ?? 1), 85 | }).ConfigureAwait(false); 86 | _brightness = brightness; 87 | } 88 | 89 | /// 90 | /// Instantly change plug to a specified brightness level 91 | /// 92 | public async Task SetBrightness(int brightness) 93 | { 94 | if (brightness < 0 || brightness > 100) throw new ArgumentException("brightness should be between 0 and 100"); 95 | 96 | await Execute("smartlife.iot.dimmer", "set_brightness", "brightness", brightness).ConfigureAwait(false); 97 | _brightness = brightness; 98 | } 99 | 100 | /// 101 | /// Configures change mode on double click of switch 102 | /// 103 | public async Task SetDoubleClickAction(DimmerMode mode, int index=0) 104 | { 105 | if (mode == DimmerMode.Preset) 106 | { 107 | if (index < 0 || index > 3) throw new ArgumentException("index should be between 0 and 3"); 108 | 109 | await Execute("smartlife.iot.dimmer", "set_double_click_action", new JObject 110 | { 111 | new JProperty("mode", mode.ToStr()), 112 | new JProperty("index", index) 113 | }).ConfigureAwait(false); 114 | } 115 | else 116 | await Execute("smartlife.iot.dimmer", "set_double_click_action", "mode", mode.ToStr()).ConfigureAwait(false); 117 | 118 | _options.DoubleClickAction = mode; 119 | } 120 | 121 | /// 122 | /// Configures change mode on long press of switch 123 | /// 124 | public async Task SetLongPressAction(DimmerMode mode, int index=0) 125 | { 126 | if (mode == DimmerMode.Preset) 127 | { 128 | if (index < 0 || index > 3) throw new ArgumentException("index should be between 0 and 3"); 129 | 130 | await Execute("smartlife.iot.dimmer", "set_long_press_action", new JObject 131 | { 132 | new JProperty("mode", mode.ToStr()), 133 | new JProperty("index", index) 134 | }).ConfigureAwait(false); 135 | } 136 | else 137 | await Execute("smartlife.iot.dimmer", "set_long_press_action", "mode", mode.ToStr()).ConfigureAwait(false); 138 | 139 | _options.LongPressAction = mode; 140 | } 141 | 142 | /// 143 | /// Configures speed of fade on transition 144 | /// 145 | public async Task SetFadeOnTime(int fadeOnTime) 146 | { 147 | if (fadeOnTime < 0) throw new ArgumentException("fadeOnTime should be a positive number"); 148 | 149 | await Execute("smartlife.iot.dimmer", "set_fade_on_time", "fadeTime", fadeOnTime).ConfigureAwait(false); 150 | _options.FadeOnTime = fadeOnTime; 151 | } 152 | 153 | /// 154 | /// Configures speed of fade off transition 155 | /// 156 | public async Task SetFadeOffTime(int fadeOffTime) 157 | { 158 | if (fadeOffTime < 0) throw new ArgumentException("fadeOffTime should be a positive number"); 159 | 160 | await Execute("smartlife.iot.dimmer", "set_fade_on_time", "fadeTime", fadeOffTime).ConfigureAwait(false); 161 | _options.FadeOffTime = fadeOffTime; 162 | } 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /tplink-smartdevices/Devices/TPLinkSmartMeterPlug.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Threading.Tasks; 5 | using TPLinkSmartDevices.Data; 6 | 7 | namespace TPLinkSmartDevices.Devices 8 | { 9 | public class TPLinkSmartMeterPlug : TPLinkSmartPlug 10 | { 11 | private const double WATTS_IN_KILOWATT = 1000d; 12 | private dynamic _gainData; 13 | 14 | public PowerData CurrentPowerUsage { get; private set; } 15 | public uint VGain => _gainData.vgain; 16 | public uint IGain => _gainData.igain; 17 | 18 | public TPLinkSmartMeterPlug(string hostname) : base(hostname) 19 | { 20 | Task.Run(async() => 21 | { 22 | await Refresh(); 23 | }).GetAwaiter().GetResult(); 24 | } 25 | 26 | private TPLinkSmartMeterPlug() { } 27 | 28 | public static new async Task Create(string hostname, int port = 9999) 29 | { 30 | var p = new TPLinkSmartMeterPlug() { Hostname = hostname, Port = port }; 31 | await p.Refresh().ConfigureAwait(false); 32 | return p; 33 | } 34 | 35 | public new async Task Refresh() 36 | { 37 | dynamic powerdata = await Execute("emeter", "get_realtime").ConfigureAwait(false); 38 | CurrentPowerUsage = new PowerData(powerdata , HardwareVersion); 39 | _gainData = await Execute("emeter", "get_vgain_igain").ConfigureAwait(false); 40 | await base.Refresh().ConfigureAwait(false); 41 | } 42 | 43 | /// 44 | /// Erases all emeter statistics 45 | /// 46 | public async Task EraseStats() 47 | { 48 | await Execute("emeter", "erase_emeter_stat").ConfigureAwait(false); 49 | } 50 | 51 | /// 52 | /// Query collected usage statistics from a specific month 53 | /// 54 | /// Dictionary<DateTime, float> of each day in a month and energy consumption of that day in kWh 55 | /// month of : ranging from 1(january) to 12(december) 56 | /// 57 | public async Task> GetMonthStats(int month, int year) 58 | { 59 | dynamic result = await Execute("emeter", "get_daystat", new JObject 60 | { 61 | new JProperty("month", month), 62 | new JProperty("year", year) 63 | }, null).ConfigureAwait(false); 64 | var stats = new Dictionary(); 65 | foreach (dynamic day_stat in result.day_list) 66 | { 67 | stats.Add(new DateTime((int)day_stat.year, (int)day_stat.month, (int)day_stat.day), (float)(day_stat.energy ?? (day_stat.energy_wh / WATTS_IN_KILOWATT))); 68 | } 69 | return stats; 70 | } 71 | 72 | /// 73 | /// Query collected usage statistics over the course of a year 74 | /// 75 | /// Dictionary<int, float> of months and energy consumption in kWh 76 | /// year of stats 77 | public async Task> GetYearStats(int year) 78 | { 79 | if (year > DateTime.Now.Year || year < 2010) throw new ArgumentOutOfRangeException($"Can't get stats for {year}. Invalid year!"); 80 | 81 | dynamic result = await Execute("emeter", "get_monthstat", "year", year).ConfigureAwait(false); 82 | var stats = new Dictionary(); 83 | foreach (dynamic month_stat in result.month_list) 84 | { 85 | stats.Add((int)month_stat.month, (float)(month_stat.energy ?? (month_stat.energy_wh / WATTS_IN_KILOWATT))); 86 | } 87 | return stats; 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /tplink-smartdevices/Devices/TPLinkSmartMultiPlug.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Linq; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace TPLinkSmartDevices.Devices 10 | { 11 | public class TPLinkSmartMultiPlug : TPLinkSmartDevice 12 | { 13 | /// 14 | /// If the all outlet relais are powered on 15 | /// 16 | public bool AllOutletsPowered { get; private set; } 17 | 18 | /// 19 | /// If the LED on the smart plug is on 20 | /// 21 | public bool LedOn { get; private set; } 22 | 23 | public string[] Features { get; private set; } 24 | 25 | public int OutletCount { get; private set; } 26 | 27 | public Outlet[] Outlets { get; private set; } 28 | 29 | public TPLinkSmartMultiPlug(string hostname, int port = 9999) : base(hostname, port) 30 | { 31 | Task.Run(() => Refresh()).GetAwaiter().GetResult(); 32 | } 33 | 34 | private TPLinkSmartMultiPlug() { } 35 | 36 | public static async Task Create(string hostname, int port = 9999) 37 | { 38 | var p = new TPLinkSmartMultiPlug() { Hostname = hostname, Port = port }; 39 | await p.Refresh().ConfigureAwait(false); 40 | return p; 41 | } 42 | 43 | /// 44 | /// Refresh device information 45 | /// 46 | public async Task Refresh() 47 | { 48 | dynamic sysInfo = await Execute("system", "get_sysinfo").ConfigureAwait(false); 49 | 50 | JObject info = JObject.Parse(Convert.ToString(sysInfo)); 51 | bool hasChildren = info["children"] != null; 52 | 53 | if (!hasChildren) throw new Exception("This plug does not have multiple outlets. use TPLinkSmartPlug instead!"); 54 | 55 | OutletCount = (int)sysInfo.child_num; 56 | Outlets = JsonConvert.DeserializeObject>(Convert.ToString(sysInfo.children)).ToArray(); 57 | this.AllOutletsPowered = !this.Outlets.Any(o => o.OutletPowered == false); 58 | 59 | Features = ((string)sysInfo.feature).Split(':'); 60 | LedOn = !(bool)sysInfo.led_off; 61 | 62 | await Refresh((object)sysInfo).ConfigureAwait(false); 63 | } 64 | 65 | public override async Task SetPoweredOn(bool value) 66 | { 67 | await Execute("system", "set_relay_state", "state", value ? 1 : 0).ConfigureAwait(false); 68 | this.AllOutletsPowered = value; 69 | } 70 | 71 | /// 72 | /// Send command which changes power state to plug 73 | /// 74 | public async Task SetPoweredOn(bool value, int outletId = -1) 75 | { 76 | if (outletId > OutletCount - 1 || outletId < -1) throw new ArgumentException("Plug does not have a outlet with specified id"); 77 | 78 | //toggle all outlets of plug 79 | if (OutletCount == 1 || outletId == -1) 80 | { 81 | await Execute("system", "set_relay_state", "state", value ? 1 : 0).ConfigureAwait(false); 82 | this.AllOutletsPowered = value; 83 | } 84 | //toggle specific outlet 85 | else 86 | { 87 | JObject root = new JObject { 88 | new JProperty("context", new JObject { new JProperty("child_ids", GetPlugID(outletId)) }), 89 | new JProperty("system", new JObject { 90 | new JProperty("set_relay_state", 91 | new JObject { new JProperty("state", value ? 1 : 0) }) 92 | }) 93 | }; 94 | 95 | string message = root.ToString(Formatting.None); 96 | await Execute("system", "set_relay_state", message).ConfigureAwait(false); 97 | this.Outlets[outletId].OutletPowered = value; 98 | this.AllOutletsPowered = !this.Outlets.Any(o => o.OutletPowered == false); 99 | } 100 | } 101 | 102 | private object GetPlugID(int outletId) 103 | { 104 | return JArray.FromObject(new[] { $"{DeviceId}0{outletId}" }); 105 | } 106 | 107 | /// 108 | /// Send command which enables or disables night mode (LED state) 109 | /// 110 | public async Task SetLedOn(bool value) 111 | { 112 | await Execute("system", "set_led_off", "off", value ? 0 : 1).ConfigureAwait(false); 113 | this.LedOn = value; 114 | } 115 | 116 | public class Outlet 117 | { 118 | [JsonProperty("id")] 119 | public string Id { get; private set; } 120 | 121 | [JsonProperty("state")] 122 | public bool OutletPowered { get; set; } 123 | 124 | [JsonProperty("alias")] 125 | public string Alias { get; private set; } 126 | 127 | [JsonProperty("on_time")] 128 | public int OnTime { get; private set; } 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /tplink-smartdevices/Devices/TPLinkSmartPlug.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Linq; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using TPLinkSmartDevices.Data.CountDownRule; 8 | using TPLinkSmartDevices.Data.Schedule; 9 | 10 | namespace TPLinkSmartDevices.Devices 11 | { 12 | public class TPLinkSmartPlug : TPLinkSmartDevice, ICountDown, ISchedule 13 | { 14 | private const string COUNTDOWN_NAMESPACE = "count_down"; 15 | private const string SCHEDULE_NAMESPACE = "schedule"; 16 | 17 | /// 18 | /// If the outlet relay is powered on 19 | /// 20 | public bool OutletPowered { get; private set; } 21 | 22 | /// 23 | /// If the LED on the smart plug is on 24 | /// 25 | public bool LedOn { get; private set; } 26 | 27 | /// 28 | /// DateTime the relay was powered on 29 | /// 30 | public DateTime PoweredOnSince { get; private set; } 31 | 32 | public string[] Features { get; private set; } 33 | 34 | public List CountDownRules { get; private set; } 35 | public List Schedules { get; private set; } 36 | 37 | public TPLinkSmartPlug(string hostname, int port = 9999) : base(hostname, port) 38 | { 39 | Task.Run(() => Refresh()).GetAwaiter().GetResult(); 40 | } 41 | 42 | protected TPLinkSmartPlug() { } 43 | 44 | public static async Task Create(string hostname, int port = 9999) 45 | { 46 | var p = new TPLinkSmartPlug() { Hostname = hostname, Port = port }; 47 | await p.Refresh().ConfigureAwait(false); 48 | return p; 49 | } 50 | 51 | /// 52 | /// Refresh device information 53 | /// 54 | public async Task Refresh() 55 | { 56 | dynamic sysInfo = await Execute("system", "get_sysinfo").ConfigureAwait(false); 57 | 58 | JObject info = JObject.Parse(Convert.ToString(sysInfo)); 59 | bool hasChildren = info["children"] != null; 60 | 61 | if (hasChildren) throw new Exception("this plug has multiple outlets. use TPLinkSmartMultiPlug instead!"); 62 | 63 | OutletPowered = (int)sysInfo.relay_state == 1; 64 | Features = ((string)sysInfo.feature).Split(':'); 65 | LedOn = !(bool)sysInfo.led_off; 66 | 67 | if ((int)sysInfo.on_time == 0) 68 | PoweredOnSince = default(DateTime); 69 | else 70 | PoweredOnSince = DateTime.Now - TimeSpan.FromSeconds((int)sysInfo.on_time); 71 | 72 | await RetrieveCountDownRules().ConfigureAwait(false); 73 | await RetrieveSchedules().ConfigureAwait(false); 74 | await Refresh((object)sysInfo).ConfigureAwait(false); 75 | } 76 | 77 | /// 78 | /// Send command which changes power state to plug 79 | /// 80 | public override async Task SetPoweredOn(bool value) 81 | { 82 | await Execute("system", "set_relay_state", "state", value ? 1 : 0).ConfigureAwait(false); 83 | this.OutletPowered = value; 84 | } 85 | 86 | /// 87 | /// Send command which changes power state to plug 88 | /// 89 | [Obsolete("Use TPLinkSmartPlug.SetPoweredOn(bool) instead")] 90 | public void SetOutletPowered(bool value) 91 | { 92 | Task.Run(async () => 93 | { 94 | await Execute("system", "set_relay_state", "state", value ? 1 : 0).ConfigureAwait(false); 95 | this.OutletPowered = value; 96 | }); 97 | } 98 | 99 | /// 100 | /// Send command which enables or disables night mode (LED state) 101 | /// 102 | public async Task SetLedOn(bool value) 103 | { 104 | await Execute("system", "set_led_off", "off", value ? 0 : 1).ConfigureAwait(false); 105 | this.LedOn = value; 106 | } 107 | 108 | public async Task RetrieveCountDownRules() 109 | { 110 | CountDownRules = await this.RetrieveCountDownRules(COUNTDOWN_NAMESPACE); 111 | } 112 | 113 | public async Task AddCountDownRule(CountDownRule cdr) 114 | { 115 | if (CountDownRules.Any(c => c.Id == cdr.Id)) throw new Exception("countdown rule with specified id already exists"); 116 | 117 | cdr = await this.AddCountDownRule(COUNTDOWN_NAMESPACE, cdr); 118 | CountDownRules.Add(cdr); 119 | } 120 | 121 | public async Task EditCountDownRule(string id, bool? enabled = null, int? delay = null, bool? poweredOn = null, string name = null) 122 | { 123 | CountDownRule cdr = CountDownRules.Find(c => c.Id == id); 124 | 125 | if (cdr == null) throw new Exception("plug has no countdown rule with specified id"); 126 | 127 | cdr.Enabled = enabled ?? cdr.Enabled; 128 | cdr.Delay = delay ?? cdr.Delay; 129 | cdr.PoweredOn = poweredOn ?? cdr.PoweredOn; 130 | cdr.Name = name ?? cdr.Name; 131 | 132 | await this.EditCountDownRule(COUNTDOWN_NAMESPACE, cdr); 133 | } 134 | 135 | public async Task EditCountDownRule(CountDownRule newCdr) 136 | { 137 | if (newCdr.Id == null) throw new Exception("countdown rule id is required"); 138 | if (!CountDownRules.Any(c => c.Id == newCdr.Id)) throw new Exception("plug has no countdown rule with specified id"); 139 | 140 | CountDownRule cdr = CountDownRules.Find(c => c.Id == newCdr.Id); 141 | cdr.Enabled = newCdr.Enabled; 142 | cdr.Delay = newCdr.Delay; 143 | cdr.PoweredOn = newCdr.PoweredOn; 144 | cdr.Name = newCdr.Name ?? cdr.Name; 145 | 146 | await this.EditCountDownRule(COUNTDOWN_NAMESPACE, cdr); 147 | } 148 | 149 | 150 | public async Task DeleteCountDownRule(string id) 151 | { 152 | dynamic result = await Execute(COUNTDOWN_NAMESPACE, "delete_rule", "id", id).ConfigureAwait(false); 153 | 154 | CountDownRules.RemoveAll(c => c.Id == id); 155 | } 156 | 157 | public async Task DeleteAllCountDownRules() 158 | { 159 | dynamic result = await Execute(COUNTDOWN_NAMESPACE, "delete_all_rules").ConfigureAwait(false); 160 | 161 | CountDownRules.Clear(); 162 | } 163 | 164 | public async Task RetrieveSchedules() 165 | { 166 | Schedules = await this.RetrieveSchedules(SCHEDULE_NAMESPACE); 167 | } 168 | 169 | public async Task AddSchedule(Schedule schedule) 170 | { 171 | await this.AddSchedule(SCHEDULE_NAMESPACE, schedule); 172 | } 173 | 174 | public async Task EditSchedule(Schedule schedule) 175 | { 176 | await this.EditSchedule(SCHEDULE_NAMESPACE, schedule); 177 | } 178 | 179 | public async Task DeleteSchedule(string id) 180 | { 181 | dynamic result = await Execute(SCHEDULE_NAMESPACE, "delete_rule", "id", id).ConfigureAwait(false); 182 | Schedules.RemoveAll(c => c.Id == id); 183 | } 184 | 185 | public async Task DeleteSchedules() 186 | { 187 | dynamic result = await Execute(SCHEDULE_NAMESPACE, "delete_all_rules").ConfigureAwait(false); 188 | Schedules.Clear(); 189 | } 190 | } 191 | } -------------------------------------------------------------------------------- /tplink-smartdevices/Events/DeviceFoundEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using TPLinkSmartDevices.Devices; 5 | 6 | namespace TPLinkSmartDevices.Events 7 | { 8 | public class DeviceFoundEventArgs : EventArgs 9 | { 10 | public TPLinkSmartDevice Device; 11 | 12 | public DeviceFoundEventArgs(TPLinkSmartDevice device) 13 | { 14 | Device = device; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tplink-smartdevices/Messaging/IMessageCache.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace TPLinkSmartDevices.Messaging 4 | { 5 | public abstract class IMessageCache 6 | { 7 | public abstract Task Request(SmartHomeProtocolMessage message, string hostname, int port = 9999); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tplink-smartdevices/Messaging/ManualMessageCache.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | 5 | namespace TPLinkSmartDevices.Messaging 6 | { 7 | public class ManualMessageCache : IMessageCache 8 | { 9 | private List _cache = new List(); 10 | 11 | public void Flush() 12 | { 13 | _cache.Clear(); 14 | } 15 | 16 | public override async Task Request(SmartHomeProtocolMessage message, string hostname, int port = 9999) 17 | { 18 | var cachedMessage = _cache.FirstOrDefault(c => c.Matches(message, hostname, port)); 19 | 20 | if (cachedMessage != null) 21 | return cachedMessage; 22 | 23 | var result = await message.Execute(hostname, port).ConfigureAwait(false); 24 | _cache.Add(new MessageCacheItem(result, hostname, port)); 25 | return result; 26 | } 27 | 28 | protected class MessageCacheItem 29 | { 30 | internal int Hash { get; set; } 31 | internal string Hostname { get; set; } 32 | internal int Port { get; set; } 33 | internal dynamic MessageResult { get; set; } 34 | 35 | internal MessageCacheItem(dynamic messageResult, string hostname, int port) 36 | { 37 | MessageResult = messageResult; 38 | Hostname = hostname; 39 | Port = port; 40 | } 41 | 42 | internal bool Matches(SmartHomeProtocolMessage message, string hostname, int port) 43 | { 44 | if (Hostname != hostname || Port != port) 45 | return false; 46 | 47 | return message.MessageHash == Hash; 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tplink-smartdevices/Messaging/NoMessageCache.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace TPLinkSmartDevices.Messaging 4 | { 5 | public class NoMessageCache : IMessageCache 6 | { 7 | public override async Task Request(SmartHomeProtocolMessage message, string hostname, int port = 9999) 8 | { 9 | return await message.Execute(hostname, port).ConfigureAwait(false); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tplink-smartdevices/Messaging/SmartHomeProtocolEncoder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Text; 4 | 5 | namespace TPLinkSmartDevices.Messaging 6 | { 7 | internal static class SmartHomeProtocolEncoder 8 | { 9 | const byte INITIALIZATION_VECTOR = 171; 10 | 11 | internal static byte[] Encrypt(string data) 12 | { 13 | var encryptedMessage = Encrypt(Encoding.ASCII.GetBytes(data)); 14 | 15 | var lengthBytes = BitConverter.GetBytes((UInt32)encryptedMessage.Length); 16 | if (BitConverter.IsLittleEndian) // this value needs to be in big-endian 17 | lengthBytes = lengthBytes.Reverse().ToArray(); 18 | 19 | return lengthBytes.Concat(encryptedMessage).ToArray(); 20 | } 21 | 22 | internal static byte[] Encrypt(byte[] data) 23 | { 24 | var result = new byte[data.Length]; 25 | var key = INITIALIZATION_VECTOR; // TP-Link Constant 26 | for (int i = 0; i < data.Length; i++) 27 | { 28 | result[i] = (byte)(key ^ data[i]); 29 | key = result[i]; 30 | } 31 | 32 | return result; 33 | } 34 | 35 | internal static byte[] Decrypt(byte[] data) 36 | { 37 | var buf = (byte[])data.Clone(); 38 | var key = INITIALIZATION_VECTOR; // TP-Link Constant 39 | for (int i = 0; i < data.Length; i++) 40 | { 41 | var nextKey = buf[i]; 42 | buf[i] = (byte)(key ^ buf[i]); 43 | key = nextKey; 44 | } 45 | return buf; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tplink-smartdevices/Messaging/SmartHomeProtocolMessage.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net.Sockets; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace TPLinkSmartDevices.Messaging 10 | { 11 | public class SmartHomeProtocolMessage 12 | { 13 | public int MessageHash 14 | { 15 | get 16 | { 17 | var data = Encoding.ASCII.GetBytes(Message ?? JSON); 18 | unchecked 19 | { 20 | const int p = 16777619; 21 | int hash = (int)2166136261; 22 | 23 | for (int i = 0; i < data.Length; i++) 24 | hash = (hash ^ data[i]) * p; 25 | 26 | hash += hash << 13; 27 | hash ^= hash >> 7; 28 | hash += hash << 3; 29 | hash ^= hash >> 17; 30 | hash += hash << 5; 31 | return hash; 32 | } 33 | } 34 | } 35 | 36 | public string JSON 37 | { 38 | get 39 | { 40 | object argObject; 41 | if (Value != null) 42 | argObject = new JObject { new JProperty(Argument.ToString(), Value) }; 43 | else 44 | argObject = Argument; 45 | 46 | var root = new JObject { new JProperty(System, new JObject { new JProperty(Command, argObject) }) }; 47 | 48 | return root.ToString(Newtonsoft.Json.Formatting.None); 49 | } 50 | } 51 | 52 | public string Message { get; private set; } 53 | 54 | public string System { get; private set; } 55 | public string Command { get; private set; } 56 | public object Argument { get; private set; } 57 | public object Value { get; private set; } 58 | 59 | internal SmartHomeProtocolMessage(string system, string command, object argument, object value) 60 | { 61 | System = system; 62 | Command = command; 63 | Argument = argument; 64 | Value = value; 65 | } 66 | 67 | internal SmartHomeProtocolMessage(string system, string command, string json) 68 | { 69 | Message = json; 70 | System = system; 71 | Command = command; 72 | } 73 | 74 | internal async Task Execute(string hostname, int port) 75 | { 76 | var messageToSend = SmartHomeProtocolEncoder.Encrypt(Message ?? JSON); 77 | 78 | var client = new TcpClient(); 79 | await client.ConnectAsync(hostname, port).ConfigureAwait(false); 80 | 81 | byte[] packet = new byte[0]; 82 | using (var stream = client.GetStream()) 83 | { 84 | await stream.WriteAsync(messageToSend, 0, messageToSend.Length).ConfigureAwait(false); 85 | 86 | int targetSize = 0; 87 | var buffer = new List(); 88 | while (true) 89 | { 90 | var chunk = new byte[1024]; 91 | var bytesReceived = await stream.ReadAsync(chunk, 0, chunk.Length).ConfigureAwait(false); 92 | 93 | if (!buffer.Any()) 94 | { 95 | var lengthBytes = chunk.Take(4).ToArray(); 96 | if (BitConverter.IsLittleEndian) 97 | lengthBytes = lengthBytes.Reverse().ToArray(); 98 | targetSize = (int)BitConverter.ToUInt32(lengthBytes, 0); 99 | } 100 | buffer.AddRange(chunk.Take(bytesReceived)); 101 | 102 | if (buffer.Count == targetSize + 4) 103 | break; 104 | } 105 | 106 | packet = buffer.Skip(4).Take(targetSize).ToArray(); 107 | } 108 | client.Dispose(); 109 | 110 | var decrypted = Encoding.ASCII.GetString(SmartHomeProtocolEncoder.Decrypt(packet)).Trim('\0'); 111 | 112 | var subResult = (dynamic)((JObject)JObject.Parse(decrypted)[System])[Command]; 113 | if (subResult?["err_code"] != null && subResult?.err_code != 0) 114 | throw new Exception($"Protocol error {subResult.err_code} ({subResult.err_msg})"); 115 | 116 | return subResult; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /tplink-smartdevices/Messaging/TimeGatedMessageCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace TPLinkSmartDevices.Messaging 7 | { 8 | public class TimeGatedMessageCache : IMessageCache 9 | { 10 | public int TimeGateResetSeconds { get; set; } = 10; 11 | 12 | private List _cache = new List(); 13 | 14 | public TimeGatedMessageCache(int resetTimeSeconds = 10) 15 | { 16 | TimeGateResetSeconds = resetTimeSeconds; 17 | } 18 | 19 | public override async Task Request(SmartHomeProtocolMessage message, string hostname, int port) 20 | { 21 | var cachedMessage = _cache.FirstOrDefault(c => c.Matches(message, hostname, port)); 22 | 23 | if (cachedMessage != null) 24 | { 25 | if (cachedMessage.IsExpired(TimeGateResetSeconds)) 26 | _cache.Remove(cachedMessage); 27 | else 28 | return cachedMessage.MessageResult; 29 | } 30 | 31 | var result = await message.Execute(hostname, port).ConfigureAwait(false); 32 | _cache.Add(new MessageCacheItem(result, hostname, port)); 33 | return result; 34 | } 35 | 36 | protected class MessageCacheItem 37 | { 38 | internal int Hash { get; set; } 39 | internal string Hostname { get; set; } 40 | internal int Port { get; set; } 41 | internal dynamic MessageResult { get; set; } 42 | internal DateTime Cached { get; set; } 43 | 44 | internal MessageCacheItem(dynamic messageResult, string hostname, int port) 45 | { 46 | MessageResult = messageResult; 47 | Hostname = hostname; 48 | Port = port; 49 | Cached = DateTime.Now; 50 | } 51 | 52 | internal bool IsExpired(int expirySeconds) 53 | { 54 | return Cached.AddSeconds(expirySeconds) < DateTime.Now; 55 | } 56 | 57 | internal bool Matches(SmartHomeProtocolMessage message, string hostname, int port) 58 | { 59 | if (Hostname != hostname || Port != port) 60 | return false; 61 | 62 | return message.MessageHash == Hash; 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /tplink-smartdevices/TPLinkDiscovery.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Net.Sockets; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using TPLinkSmartDevices.Devices; 10 | using Microsoft.CSharp.RuntimeBinder; 11 | using TPLinkSmartDevices.Events; 12 | using TPLinkSmartDevices.Messaging; 13 | 14 | namespace TPLinkSmartDevices 15 | { 16 | public class TPLinkDiscovery 17 | { 18 | public event EventHandler DeviceFound; 19 | 20 | private int PORT_NUMBER = 9999; 21 | 22 | public List DiscoveredDevices { get; private set; } 23 | 24 | private UdpClient udp; 25 | 26 | private bool discoveryComplete = false; 27 | 28 | public TPLinkDiscovery() 29 | { 30 | DiscoveredDevices = new List(); 31 | } 32 | 33 | public async Task> Discover(int port=9999, int timeout=5000, string target = "255.255.255.255") 34 | { 35 | discoveryComplete = false; 36 | 37 | DiscoveredDevices.Clear(); 38 | PORT_NUMBER = port; 39 | 40 | await SendDiscoveryRequestAsync(target).ConfigureAwait(false); 41 | 42 | udp = new UdpClient(PORT_NUMBER) 43 | { 44 | EnableBroadcast = true 45 | }; 46 | 47 | return await Task.WhenAny(Task.Delay(timeout), Receive()) 48 | .ContinueWith(t => 49 | { 50 | discoveryComplete = true; 51 | udp.Close(); 52 | udp = null; 53 | 54 | return DiscoveredDevices; 55 | }) 56 | .ConfigureAwait(false); 57 | } 58 | 59 | private async Task Receive() 60 | { 61 | while (true) 62 | { 63 | if (discoveryComplete) //Prevent ObjectDisposedException/NullReferenceException when the Close() function is called 64 | return; 65 | 66 | IPEndPoint ip = new IPEndPoint(IPAddress.Any, PORT_NUMBER); 67 | UdpReceiveResult result = await udp.ReceiveAsync().ConfigureAwait(false); 68 | ip = result.RemoteEndPoint; 69 | var message = Encoding.ASCII.GetString(Messaging.SmartHomeProtocolEncoder.Decrypt(result.Buffer)); 70 | 71 | TPLinkSmartDevice device = null; 72 | try 73 | { 74 | dynamic sys_info = ((dynamic)JObject.Parse(message)).system.get_sysinfo; 75 | string model = (string)sys_info.model; 76 | if (model != null) 77 | { 78 | if (model.StartsWith("HS110")) 79 | device = await TPLinkSmartMeterPlug.Create(ip.Address.ToString()).ConfigureAwait(false); 80 | else if (model.StartsWith("HS300") || model.StartsWith("KP303") || model.StartsWith("HS107")) 81 | device = await TPLinkSmartMultiPlug.Create(ip.Address.ToString()).ConfigureAwait(false); 82 | else if (model.StartsWith("HS220")) 83 | device = await TPLinkSmartDimmer.Create(ip.Address.ToString()).ConfigureAwait(false); 84 | else if (model.StartsWith("HS")) 85 | device = await TPLinkSmartPlug.Create(ip.Address.ToString()).ConfigureAwait(false); 86 | else if (model.StartsWith("KL") || model.StartsWith("LB")) 87 | device = await TPLinkSmartBulb.Create(ip.Address.ToString()).ConfigureAwait(false); 88 | } 89 | } 90 | catch (RuntimeBinderException) 91 | { 92 | //discovered wrong device 93 | } 94 | 95 | if (device != null) 96 | { 97 | DiscoveredDevices.Add(device); 98 | OnDeviceFound(device); 99 | } 100 | } 101 | } 102 | 103 | private async Task SendDiscoveryRequestAsync(string target) 104 | { 105 | UdpClient client = new UdpClient(PORT_NUMBER); 106 | IPEndPoint ip = new IPEndPoint(IPAddress.Parse(target), PORT_NUMBER); 107 | 108 | var discoveryJson = JObject.FromObject(new 109 | { 110 | system = new { get_sysinfo = (object)null }, 111 | emeter = new { get_realtime = (object)null } 112 | }).ToString(Newtonsoft.Json.Formatting.None); 113 | var discoveryPacket = Messaging.SmartHomeProtocolEncoder.Encrypt(discoveryJson).ToArray(); 114 | 115 | var bytes = discoveryPacket.Skip(4).ToArray(); 116 | client.EnableBroadcast = true; 117 | await client.SendAsync(bytes, bytes.Length, ip).ConfigureAwait(false); 118 | client.Close(); 119 | client.Dispose(); 120 | } 121 | 122 | private void OnDeviceFound(TPLinkSmartDevice device) 123 | { 124 | DeviceFound?.Invoke(this, new DeviceFoundEventArgs(device)); 125 | } 126 | 127 | /// 128 | /// Makes device connect to specified network. Host who runs the application needs to be connected to the open configuration network! (TP-Link_Smart Plug_XXXX or similar) 129 | /// 130 | public async Task Associate(string ssid, string password, int type = 3) 131 | { 132 | dynamic scan = await new SmartHomeProtocolMessage("netif","get_scaninfo","refresh","1").Execute("192.168.0.1", 9999).ConfigureAwait(false); 133 | 134 | if (scan == null || !scan.ToString().Contains(ssid)) 135 | { 136 | throw new Exception("Couldn't find network!"); 137 | } 138 | 139 | JArray networks = JArray.Parse(Convert.ToString(scan.ap_list)); 140 | JToken network = networks.First(n => n["ssid"].ToString() == ssid); 141 | type = (int)network["key_type"]; 142 | 143 | dynamic result = await new SmartHomeProtocolMessage("netif", "set_stainfo", new JObject 144 | { 145 | new JProperty("ssid", ssid), 146 | new JProperty("password", password), 147 | new JProperty("key_type", type) 148 | }, null).Execute("192.168.0.1", 9999).ConfigureAwait(false); 149 | 150 | if (result == null) 151 | { 152 | throw new Exception("Couldn't connect to network. Check password"); 153 | } 154 | else if (result["err_code"] != null && result.err_code != 0) 155 | throw new Exception($"Protocol error {result.err_code} ({result.err_msg})"); 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /tplink-smartdevices/TPLinkSmartDevices.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | tplink-smartdevices 6 | CodeBardian 7 | 8 | .NET Standard 2.0 Library for Discovering and Operating TP-Link Smart Devices (HS, LB and KL-series) 9 | https://github.com/CodeBardian/tplink-smartdevices-netstandard 10 | https://github.com/CodeBardian/tplink-smartdevices-netstandard 11 | TP-Link, Smart Home 12 | Apache-2.0 13 | GitHub 14 | TPLinkSmartDevices 15 | 2.0.1 16 | 8.0 17 | 18 | 19 | 20 | bin\release\netstandard2.0\tplink-smartdevices.xml 21 | 1701;1702;1591 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | --------------------------------------------------------------------------------