Skip to content

mikefactorial/NextGenPluginDemo

Repository files navigation

NextGenPluginDemo

A complete demo showing how to:

  • Control TP-Link/Kasa smart bulbs and plugs via an Azure Functions app (.NET 8 isolated)
  • Share typed models between services and plugins
  • Call the Functions from Dataverse plugins (net462) with managed identity, environment variables, and HTTP helpers
  • Optionally run a local Node/TypeScript REST service that talks to devices on your LAN

This repo contains three main projects:

  • Functions: Functions/NextGenDemo.Functions.csproj
  • Plugins (Dataverse): Plugins/NextGenDemo.Plugins.csproj
  • Shared models: Shared/NextGenDemo.Shared.csproj
  • Optional local device API: KasaLightAPI/ (Node 18+)

Quick start

Prerequisites

  • Windows with PowerShell (recommended), or any OS with a terminal
  • .NET 8 SDK
  • Node.js 18+ (only if you plan to run the local Kasa API)
  • Azure Functions Core Tools (optional if you prefer func start)

Clone and restore

git clone https://github.com/mikefactorial/NextGenPluginDemo.git
cd NextGenPluginDemo
dotnet restore

Run the local Kasa device API (optional but recommended)

The Functions app calls a REST API that talks to your bulbs/plugs on the LAN. You can run the included Node service or point to an existing endpoint (e.g., ngrok).

  1. Configure KasaLightAPI
  • Copy KasaLightAPI/.env.example to KasaLightAPI/.env
  • Set API_KEY to a secret value (match this in the Functions settings)
  1. Install and start
cd KasaLightAPI
npm i
npm run dev
# Service starts on http://localhost:3000

Key endpoints (see KasaLightAPI/README.md for full list):

  • GET /api/health
  • GET /api/devices
  • GET /api/test/:ip/on|off|red|green|blue|yellow|purple|white
  • POST /api/bulb/:ip/hex body: { hex: "#FF0000" }
  • POST /api/bulb/:ip/color body: { hue, saturation, brightness? }
  • POST /api/bulb/:ip/temperature body: { kelvin }
  • POST /api/bulb/:ip/alias body: { alias }

Configure and run the Azure Functions app

Configuration lives in Functions/local.settings.json and is read as flat keys in Functions/Program.cs:

  • BulbApiBaseUrl — e.g., http://localhost:3000/api (for the local Node API) or your ngrok URL
  • BulbApiKey — must match the API_KEY used by the device API if authentication is enabled

Example (Functions/local.settings.json):

{
	"IsEncrypted": false,
	"Values": {
		"AzureWebJobsStorage": "UseDevelopmentStorage=true",
		"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
		"BulbApiBaseUrl": "http://localhost:3000/api",
		"BulbApiKey": "your-local-api-key"
	}
}

Start the Functions app

# Default launch profile runs on port 7210 (see Functions/Properties/launchSettings.json)
dotnet run --project Functions/NextGenDemo.Functions.csproj -- --port 7210

# Base URL: http://localhost:7210/api

Main files

  • Functions entry: Functions/Program.cs
  • HTTP functions: Functions/BulbFunctions.cs
  • Service + settings: Functions/Services/BulbControlService.cs, Functions/Services/BulbApiSettings.cs
  • Models: Shared/Models/BulbControlRequest.cs, Shared/Models/DeviceInfo.cs

HTTP endpoints (Functions)

Implemented in Functions/BulbFunctions.cs.

  1. POST /api/BulbQuickAction
  • Body: { "bulbIP": "<ip>", "action": "on|off|red|green|blue|yellow|purple|white" }
  1. POST /api/ControlBulb
  • Body uses strongly-typed models with enum strings for pattern and transition; examples in Functions/README_API_Examples.json.
  • Minimal example:
{
	"bulbIP": "192.168.1.50",
	"colors": [
		{ "hex": "#FF0000", "durationMs": 1000 },
		{ "hex": "#0000FF", "durationMs": 1000 }
	],
	"pattern": { "type": "Sequential", "repeatCount": 1, "transition": "Fade", "transitionDurationMs": 500 }
}
  1. GET /api/ListDevices
  • Returns array of devices discovered by the backend API
  1. POST /api/devices/{deviceIp}/alias
  • Body: { "alias": "Living Room Light" }

More payloads and curl examples: Functions/README_API_Examples.json

Local test scripts (PowerShell)

Run from the Functions folder while the app is running:

cd Functions
./test-bulb-functions.ps1
./test-device-functions.ps1

Troubleshooting tips and known fixes: Functions/TROUBLESHOOTING.md Device management notes: Functions/DEVICE_MANAGEMENT.md

Dataverse Plugins (net462)

Core classes

  • Base: Plugins/PluginBase.cs
  • Example plugin that calls the Functions: Plugins/BulbApi.cs
  • Environment variables helper: Plugins/Types/EnvironmentVariableService.cs
  • HTTP and identity helpers: Plugins/Integration/HttpClientWrapper.cs, Plugins/Integration/JwtTokenProvider.cs, Plugins/Integration/AzureVariables.cs

Environment variable schema names used by the plugins (Dataverse):

  • mf_devicelisturl — Device list Function URL
  • mf_bulbquickactionurl — Quick action Function URL
  • mf_bulbcontrolurl — Control Function URL
  • mf_bulbip — Optional default device IP (if relevant)
  • mf_azurefunctionauthscope — Azure AD scope for acquiring tokens
  • Storage (optional): mf_storagecontainername, mf_storageendpoint

Build, pack, and sign

# Build
dotnet build Plugins/NextGenDemo.Plugins.csproj

# Pack a NuGet (uses Microsoft.PowerApps.MSBuild.Plugin)
dotnet pack Plugins/NextGenDemo.Plugins.csproj -c Release

# Note: The csproj defines a signing step that runs in Visual Studio after Pack
# (see PostBuild target). You can sign manually with: dotnet nuget sign ...

See Plugins/NextGenDemo.Plugins.csproj for package metadata and the PostBuild signing target.

CI

GitHub Actions builds and tests on push/PR to master: .github/workflows/dotnet.yml.

Project structure (high level)

Functions/
	Program.cs
	BulbFunctions.cs
	Services/
		BulbControlService.cs
		BulbApiSettings.cs
	README_API_Examples.json
	DEVICE_MANAGEMENT.md
	TROUBLESHOOTING.md
Plugins/
	PluginBase.cs
	BulbApi.cs
	Integration/
	Types/
Shared/
	Models/
		BulbControlRequest.cs
		DeviceInfo.cs
KasaLightAPI/
	README.md
	package.json

Notes

  • Enum values in JSON must be strings (e.g., "Fade", "Sequential") — see Functions/TROUBLESHOOTING.md
  • Default Functions dev port is 7210 via Functions/Properties/launchSettings.json
  • Keep secrets out of source control; use local.settings.json and .env
  • The local API expects the X-API-Key header if API_KEY is set; the Functions client sends this header when BulbApiKey is configured

License

This repository is provided for demo purposes. Add your preferred license if needed.

About

Demo of Plugins in Power Platform using Managed Identities/Plugin Packages and more

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •