Python to .NET Migration Guide
Comprehensive comparison between the Python pixelblaze-client library and the .NET PixelblazeDotNet port.
Status: Wet Paint (Jan 2026) - Sprint 1-2 (protocol), Sprint 4 (feature parity), Sprint 5 (bug fixes) complete. Sprint 3 (connection resilience) parked.
Aspect
Python (pixelblaze-client)
.NET (PixelblazeDotNet)
Structure
Single 3000+ line class
11 modular classes
Async
Synchronous
All async/await
Logging
Print statements
Microsoft.Extensions.Logging
Typing
Dynamic
Strongly-typed with nullables
Caching
Minimal
Time-based caching (5 sec)
Connection
WebSocket only
WebSocket + TCP support
Message Handling
Serial, blocking
Single pipeline, serialized requests
Python
.NET
Pixelblaze (single class)
PixelblazeClient (facade)
PixelblazeSequencer
PixelblazePatterns
PixelblazeMapper
PixelblazeSettings
PixelblazeStatistics
PixelblazeBinaryBackup
PixelblazeAdvanced
PixelblazeNetworkHelper
PixelblazeEnumerator
PixelblazeDiscovery
PBB
PixelblazeBinaryBackup
PBP
PixelblazeBinaryPattern
EPE
ElectromagePatternExport
Python
.NET
Status
Pixelblaze(ipAddress)
new PixelblazeClient(ip, loggerFactory)
Ported
EnumerateAddresses()
PixelblazeDiscovery.DiscoverDevicesAsync()
Ported
EnumerateDevices()
PixelblazeClient.DiscoverClientsAsync()
Ported
getPeers()
-
Not ported
Context manager (with)
IAsyncDisposable
Ported
Python
.NET
Status
getSequencerMode()
Sequencer.GetSequencerModeAsync()
Ported
setSequencerMode()
Sequencer.SetSequencerModeAsync()
Ported
getSequencerState()
Sequencer.GetSequencerStateAsync()
Ported
setSequencerState()
Sequencer.SetSequencerStateAsync()
Ported
playSequencer()
Sequencer.PlaySequencerAsync()
Ported
pauseSequencer()
Sequencer.PauseSequencerAsync()
Ported
nextSequencer()
Sequencer.NextSequencerAsync()
Ported
getSequencerShuffleTime()
Sequencer.GetSequencerShuffleTimeAsync()
Ported
setSequencerShuffleTime()
Sequencer.SetSequencerShuffleTimeAsync()
Ported
getSequencerPlaylist()
Sequencer.GetSequencerPlaylistAsync()
Ported
setSequencerPlaylist()
Sequencer.SetSequencerPlaylistAsync()
Ported
addToSequencerPlaylist()
Sequencer.AddToSequencerPlaylistAsync()
Ported
Python
.NET
Status
getPatternList()
Patterns.GetPatternListAsync()
Ported
getActivePattern()
Patterns.GetActivePatternAsync()
Ported
setActivePattern()
Patterns.SetActivePatternAsync()
Ported
setActivePatternByName()
Patterns.SetActivePatternByNameAsync()
Ported
deletePattern()
PixelblazeClient.DeletePatternAsync()
Ported
getPatternAsEpe()
Patterns.GetPatternAsEpeAsync()
Ported
getPreviewImage()
Via PixelblazeBinaryPattern.Jpeg
Ported
getPatternSourceCode()
Advanced.GetPatternSourceCodeAsync()
Ported
getPatternControls()
Patterns.GetPatternControlsAsync()
Ported
sendPatternToRenderer()
Patterns.SendPatternToRendererAsync()
Ported
savePattern()
Patterns.SavePatternAsync()
Ported
-
Patterns.DuplicatePatternAsync()
.NET only
Python
.NET
Status
getActiveVariables()
Patterns.GetActiveVariablesAsync()
Ported
setActiveVariables()
Patterns.SetActiveVariablesAsync()
Ported
getActiveControls()
Patterns.GetActiveControlsAsync()
Ported
setActiveControls()
Patterns.SetActiveControlsAsync()
Ported
controlExists()
Patterns.ControlExistsAsync()
Ported
getColorControlName()
Patterns.GetColorControlNameAsync()
Ported
getColorControlNames()
Patterns.GetColorControlNamesAsync()
Ported
setColorControl()
Patterns.SetColorControlAsync()
Ported
Uses HTTP file operations (/pixelmap.txt, /pixelmap.dat) like Python.
Python
.NET
Status
getMapFunction()
Mapper.GetMapFunctionAsync()
Ported (HTTP)
setMapFunction()
Mapper.SetMapFunctionAsync()
Ported (HTTP)
getMapData()
Mapper.GetMapDataAsync()
Ported (HTTP)
setMapData()
Mapper.SetMapDataAsync()
Ported (HTTP)
getMapCoordinates()
Mapper.GetMapCoordinatesAsync()
Ported
setMapCoordinates()
Mapper.SetMapCoordinatesAsync()
Ported
createMapData()
Mapper.CreateMapDataAsync()
Ported
Python
.NET
Status
getConfigSettings()
Settings.GetAllSettingsAsync()
Ported
getConfigSequencer()
NetworkHelper.GetConfigSequencerAsync()
Ported (internal)
getConfigExpander()
Settings.GetConfigExpanderAsync()
Ported
getDeviceName()
Settings.GetDeviceNameAsync()
Ported
setDeviceName()
Settings.SetDeviceNameAsync()
Ported
getDiscovery()
Settings.GetDiscoveryAsync()
Ported
setDiscovery()
Settings.SetDiscoveryAsync()
Ported
getTimezone()
Settings.GetTimezoneAsync()
Ported
setTimezone()
Settings.SetTimezoneAsync()
Ported
getAutoOffEnable()
Settings.GetAutoOffEnableAsync()
Ported
setAutoOffEnable()
Settings.SetAutoOffEnableAsync()
Ported
getAutoOffStart()
Settings.GetAutoOffStartAsync()
Ported*
setAutoOffStart()
Settings.SetAutoOffStartAsync()
Ported*
getAutoOffEnd()
Settings.GetAutoOffEndAsync()
Ported*
setAutoOffEnd()
Settings.SetAutoOffEndAsync()
Ported*
getBrightnessLimit()
Settings.GetBrightnessLimitAsync()
Ported
setBrightnessLimit()
Settings.SetBrightnessLimitAsync()
Ported
getBrightnessSlider()
Settings.GetBrightnessAsync()
Ported
setBrightnessSlider()
Settings.SetBrightnessAsync()
Ported
getLedType()
Settings.GetLedTypeAsync()
Ported
setLedType()
Settings.SetLedTypeAsync()
Ported
getPixelCount()
Settings.GetPixelCountAsync()
Ported
setPixelCount()
Settings.SetPixelCountAsync()
Ported
getDataSpeed()
Settings.GetDataSpeedAsync()
Ported
setDataSpeed()
Settings.SetDataSpeedAsync()
Ported
getColorOrder()
Settings.GetColorOrderAsync()
Ported
setColorOrder()
Settings.SetColorOrderAsync()
Ported
getCpuSpeed()
Settings.GetCpuSpeedAsync()
Ported
setCpuSpeed()
Settings.SetCpuSpeedAsync()
Ported
getNetworkPowerSave()
Settings.GetNetworkPowerSaveAsync()
Ported
setNetworkPowerSave()
Settings.SetNetworkPowerSaveAsync()
Ported
getBrandName()
Settings.GetBrandNameAsync()
Ported
setBrandName()
Settings.SetBrandNameAsync()
Ported
getSimpleUiMode()
Settings.GetSimpleUiModeAsync()
Ported
setSimpleUiMode()
Settings.SetSimpleUiModeAsync()
Ported
getLearningUiMode()
Settings.GetLearningUiModeAsync()
Ported
setLearningUiMode()
Settings.SetLearningUiModeAsync()
Ported
*Note: Python uses "HH:MM" string format; .NET Settings uses string, but Advanced uses int (minutes).
Note: Pixelblaze broadcasts stats every second. Only broadcast fields are available.
Python
.NET
Status
getStatistics()
Statistics.GetAllStatisticsAsync()
Ported (broadcast fields only)
getFPS()
Statistics.GetFPSAsync()
Ported
getUptime()
Statistics.GetUptimeAsync()
Ported
getStorageSize()
Statistics.GetStorageSizeAsync()
Ported
getStorageUsed()
Statistics.GetStorageUsedAsync()
Ported
-
Statistics.GetFreeStoragePercentageAsync()
.NET only (calculated)
-
Statistics.GetFreeRAMAsync()
.NET only (mem field)
-
Statistics.GetTotalRAMAsync()
NotSupported†
-
Statistics.GetRAMPercentageUsedAsync()
NotSupported†
-
Statistics.GetPatternCountAsync()
NotSupported†
-
Statistics.GetQueueLengthAsync()
NotSupported†
-
Statistics.WaitForEmptyQueueAsync()
NotSupported†
†These methods throw NotSupportedException - data not available in Pixelblaze protocol.
Python
.NET
Status
getFileList()
BinaryBackup.GetFileListAsync()
Ported
getFile()
BinaryBackup.GetFileAsync()
Ported
putFile()
BinaryBackup.PutFileAsync()
Partial*
deleteFile()
BinaryBackup.DeleteFileAsync()
Partial*
*Note: .NET implementation currently only updates local cache, does not send to device.
Python
.NET
Status
reboot()
Advanced.RebootAsync()
Ported
installUpdate()
Advanced.InstallUpdateAsync()
Ported
getUpdateState()
Advanced.GetUpdateStateAsync()
Ported
getVersion()
Settings.GetVersionAsync()
Ported
getVersionMajor()
Settings.GetVersionMajorAsync()
Ported
getVersionMinor()
Settings.GetVersionMinorAsync()
Ported
saveBackup()
BinaryBackup.SaveAsync()
Ported
restoreFromBackup()
BinaryBackup.RestoreAsync()
Ported
Python
.NET
Status
setSendPreviewFrames()
Renderer.SetSendPreviewFramesAsync()
Ported
getPreviewFrame()
Renderer.GetPreviewFrameAsync()
Ported
pauseRenderer()
Renderer.PauseRendererAsync()
Ported
Python
.NET
Status
wsReceive()
Internal
Ported
wsSendJson()
Internal
Ported
wsSendBinary()
Internal
Ported
sendPing()
PixelblazeNetworkHelper.SendPingAsync()
Ported
Python
.NET
Status
sequencerModes
-
Not ported (use strings)
ledTypes
-
Not ported (use strings)
colorOrders
-
Not ported (use strings)
cpuSpeeds
-
Not ported (use strings)
updateStates
-
Not ported (use dynamic)
messageTypes
Internal
Ported
frameTypes
Internal
Ported
fileTypes
PixelblazeFileType
Ported
Python
.NET
Status
PBB.fromFile()
BinaryBackup.RestoreAsync()
Ported
PBB.fromIpAddress()
Constructor + RefreshCacheAsync()
Ported
PBB.fromPixelblaze()
Constructor
Ported
PBB.toFile()
BinaryBackup.SaveAsync()
Ported
PBB.toIpAddress()
-
Not ported
PBB.toPixelblaze()
-
Not ported
PBB.getFileList()
BinaryBackup.GetFileListAsync()
Ported
PBB.getFile()
BinaryBackup.GetFileAsync()
Ported
PBB.putFile()
BinaryBackup.PutFileAsync()
Partial
PBB.deleteFile()
BinaryBackup.DeleteFileAsync()
Partial
Python
.NET
Status
PBP.fromBytes()
PixelblazeBinaryPattern.FromBytes()
Ported
PBP.fromFile()
PixelblazeBinaryPattern.FromFileAsync()
Ported
PBP.fromIpAddress()
-
Not ported
PBP.fromPixelblaze()
PixelblazeBinaryPattern.FromPixelblazeAsync()
Ported
PBP.toFile()
PixelblazeBinaryPattern.ToFileAsync()
Ported
PBP.toIpAddress()
-
Not ported
PBP.toPixelblaze()
PixelblazeBinaryPattern.ToPixelblazeAsync()
Ported
PBP.toEPE()
PixelblazeBinaryPattern.ToEpe()
Ported
PBP.explode()
PixelblazeBinaryPattern.ExplodeAsync()
Ported
Properties: id, name, jpeg, byteCode, sourceCode
Same
Ported
EPE (Electromage Pattern Export)
Python
.NET
Status
EPE.fromBytes()
ElectromagePatternExport.FromBytes()
Ported
EPE.fromFile()
ElectromagePatternExport.LoadAsync()
Ported
EPE.toFile()
ElectromagePatternExport.SaveAsync()
Ported
EPE.explode()
ElectromagePatternExport.ExplodeAsync()
Ported
Properties: patternId, patternName, sourceCode, previewImage
Id, Name, SourceCode, PreviewImage
Ported
The following Python features are not yet available in .NET:
getPeers() - Peer discovery (blocked - Pixelblaze firmware doesn't implement yet)
sequencerModes - Use strings: "off", "shuffleAll", "playlist"
ledTypes - Use strings
colorOrders - Use strings
cpuSpeeds - Use strings: "80", "160", "240"
updateStates - Returns dynamic
Time synchronization
Continuous enumeration (legacy PixelblazeEnumerator)
WebSocket event subscriptions
from pixelblaze import Pixelblaze
pb = Pixelblaze ("192.168.1.100" )
patterns = pb .getPatternList ()
pb .setActivePatternByName ("Rainbow Melt" )
using PixelBlazeDotNetClient ;
using Microsoft . Extensions . Logging ;
var loggerFactory = LoggerFactory . Create ( b => b . AddConsole ( ) ) ;
var client = new PixelblazeClient ( "192.168.1.100" , loggerFactory ) ;
await client . ConnectAsync ( ) ;
var patterns = await client . Patterns . GetPatternListAsync ( ) ;
await client . Patterns . SetActivePatternByNameAsync ( "Rainbow Melt" ) ;
await client . DisposeAsync ( ) ;
from pixelblaze import Pixelblaze
for pb in Pixelblaze .EnumerateDevices ():
print (f"Found: { pb .getDeviceName ()} " )
var loggerFactory = LoggerFactory . Create ( b => b . AddConsole ( ) ) ;
var discovery = new PixelblazeDiscovery ( loggerFactory . CreateLogger < PixelblazeDiscovery > ( ) ) ;
var devices = await discovery . DiscoverDevicesAsync ( ) ;
foreach ( var device in devices )
{
var info = await discovery . GetDeviceInfoAsync ( device . IpAddress ) ;
Console . WriteLine ( $ "Found: { info ? . Name } ") ;
}
Jan 2026 Update: Sprints 1, 2, 4, and 5 complete. All major protocol and feature issues resolved.
WebSocket Frame Handling - FIXED ✓
Preview frame header size corrected (19→1 bytes)
WebSocket frame accumulation fixed (accumulate until EndOfMessage)
Color picker controls now return proper Dictionary<string, double> objects
Settings (17 getters) - FIXED ✓
All getter methods now use {"getConfig": true} and extract values from the cached response (5 second TTL).
Method
Status
SetActivePatternAsync()
✓ Uses {"activeProgramId": id}
GetPatternSourceCodeAsync()
✓ Uses {"getSources": id} with LZString decompression
DeletePatternAsync()
✓ Uses {"deleteProgram": id}
GetPatternListAsync()
✓ Handles binary response (type 7)
GetActivePatternAsync()
✓ Extracts from config cache
All commands now use correct protocol names: sequencerMode, runSequencer, nextProgram, sequenceTimer, getPlaylist.
Statistics class now reads from broadcast stats cache. Unavailable methods throw NotSupportedException.
✓ Config cache (5 second TTL)
✓ Binary message support (types 1-9)
✓ Frame chunking for large transfers
✓ LZString compression integrated
Remaining Issues (Sprint 3 - PARKED)
Deferred: Nice-to-have. Plugin has its own reconnect logic. Risk outweighs benefit.
No Auto-Reconnect - Connections don't automatically recover from network issues
No Connection Maintenance - May timeout after ~10 minutes of idle
Missing saveToFlash parameter - Settings changes may revert on reboot
WebSocket connection (ws://ip:81)
HTTP file operations (/list, /edit, /delete?path=)
UDP beacon discovery (port 1889)
Config caching (5 second TTL)
Binary message types and frame chunking
LZString compression for pattern source code
All settings getters (extract from config)
All sequencer commands
Statistics from broadcast
Device file operations (GetDeviceFileListAsync, GetDeviceFileAsync, PutDeviceFileAsync, DeleteDeviceFileAsync) use HTTP API and work correctly. Local cache operations (PutFile, DeleteFile) only update in-memory cache.
Some settings methods exist in both PixelblazeSettings and PixelblazeAdvanced:
Brand name
Timezone
Auto-off settings
Network power save
UI modes
Both now use correct protocol commands. The Advanced versions use int for auto-off times (minutes since midnight); Settings uses "HH:MM" strings.
Recommendations for Python Users
Ready for Testing - Sprint 1 & 2 fixes applied, library should work with real hardware
Use async/await - All .NET methods are async
Inject ILoggerFactory - Required for client construction
Use IAsyncDisposable - await using or explicit DisposeAsync()
Check return types - GetPatternListAsync() returns Dictionary<string, string>, not a list
Prefer subsystem access - Use client.Patterns.* instead of client.* for pattern operations
Statistics limitation - Some Python stats methods not available (throw NotSupportedException)