diff --git a/csharp/App/GpioTestingProject/GpioTestingProject.csproj b/csharp/App/GpioTestingProject/GpioTestingProject.csproj
new file mode 100644
index 000000000..a4f20b48e
--- /dev/null
+++ b/csharp/App/GpioTestingProject/GpioTestingProject.csproj
@@ -0,0 +1,16 @@
+
+
+
+ InnovEnergy.App.GpioTestingProject
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/csharp/InnovEnergy.sln b/csharp/InnovEnergy.sln
index 6c48122ab..91dc5abf0 100644
--- a/csharp/InnovEnergy.sln
+++ b/csharp/InnovEnergy.sln
@@ -1,27 +1,26 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-#
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Collector", "App\Collector\Collector.csproj", "{E3A5F3A3-72A5-47CC-85C6-2D8E962A0EC1}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Collector", "App/Collector/Collector.csproj", "{E3A5F3A3-72A5-47CC-85C6-2D8E962A0EC1}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenVpnCertificatesServer", "App\OpenVpnCertificatesServer\OpenVpnCertificatesServer.csproj", "{CF4834CB-91B7-4172-AC13-ECDA8613CD17}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenVpnCertificatesServer", "App/OpenVpnCertificatesServer/OpenVpnCertificatesServer.csproj", "{CF4834CB-91B7-4172-AC13-ECDA8613CD17}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemoteSupportConsole", "App\RemoteSupportConsole\RemoteSupportConsole.csproj", "{B1268C03-66EB-4486-8BFC-B439225D9D54}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemoteSupportConsole", "App/RemoteSupportConsole/RemoteSupportConsole.csproj", "{B1268C03-66EB-4486-8BFC-B439225D9D54}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SysTools", "Lib\SysTools\SysTools.csproj", "{4A67D79F-F0C9-4BBC-9601-D5948E6C05D3}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SysTools", "Lib/SysTools/SysTools.csproj", "{4A67D79F-F0C9-4BBC-9601-D5948E6C05D3}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebServer", "Lib\WebServer\WebServer.csproj", "{B2627B9F-41DF-44F7-A0D1-CA71FF4A007A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebServer", "Lib/WebServer/WebServer.csproj", "{B2627B9F-41DF-44F7-A0D1-CA71FF4A007A}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmuMeterDriver", "App\EmuMeterDriver\EmuMeterDriver.csproj", "{F65F33B0-3522-4008-8D1E-47EF8E4C7AC7}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmuMeterDriver", "App/EmuMeterDriver/EmuMeterDriver.csproj", "{F65F33B0-3522-4008-8D1E-47EF8E4C7AC7}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BmsTunnel", "App\BmsTunnel\BmsTunnel.csproj", "{40B45363-BE34-420B-8F87-775EE6EE3513}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BmsTunnel", "App/BmsTunnel/BmsTunnel.csproj", "{40B45363-BE34-420B-8F87-775EE6EE3513}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "App", "App", "{145597B4-3E30-45E6-9F72-4DD43194539A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Lib", "Lib", "{AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SaliMax", "App\SaliMax\SaliMax.csproj", "{25073794-D859-4824-9984-194C7E928496}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SaliMax", "App/SaliMax/SaliMax.csproj", "{25073794-D859-4824-9984-194C7E928496}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatusApi", "Lib\StatusApi\StatusApi.csproj", "{9D17E78C-8A70-43DB-A619-DC12D20D023D}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatusApi", "Lib/StatusApi/StatusApi.csproj", "{9D17E78C-8A70-43DB-A619-DC12D20D023D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Devices", "Devices", "{4931A385-24DC-4E78-BFF4-356F8D6D5183}"
EndProject
@@ -31,35 +30,35 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Victron", "Victron", "{BD8C
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Trumpf", "Trumpf", "{DDDBEFD0-5DEA-4C7C-A9F2-FDB4636CF092}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TruConvertAc", "Lib\Devices\Trumpf\TruConvertAc\TruConvertAc.csproj", "{1F4B445E-459E-44CD-813E-6D725EBB81E8}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TruConvertAc", "Lib/Devices/Trumpf/TruConvertAc/TruConvertAc.csproj", "{1F4B445E-459E-44CD-813E-6D725EBB81E8}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TruConvertDc", "Lib\Devices\Trumpf\TruConvertDc\TruConvertDc.csproj", "{F6F29829-C31A-4994-A698-E441BEA631C6}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TruConvertDc", "Lib/Devices/Trumpf/TruConvertDc/TruConvertDc.csproj", "{F6F29829-C31A-4994-A698-E441BEA631C6}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DBus", "Lib\Protocols\DBus\DBus.csproj", "{8C3C620A-087D-4DD6-B493-A47FC643F8DC}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DBus", "Lib/Protocols/DBus/DBus.csproj", "{8C3C620A-087D-4DD6-B493-A47FC643F8DC}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modbus", "Lib\Protocols\Modbus\Modbus.csproj", "{E4AE6A33-0DEB-48EB-9D57-C0C7C63FC267}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modbus", "Lib/Protocols/Modbus/Modbus.csproj", "{E4AE6A33-0DEB-48EB-9D57-C0C7C63FC267}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VeDBus", "Lib\Victron\VeDBus\VeDBus.csproj", "{50B26E29-1B99-4D07-BCA5-359CD550BBAA}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VeDBus", "Lib/Victron/VeDBus/VeDBus.csproj", "{50B26E29-1B99-4D07-BCA5-359CD550BBAA}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VictronVRM", "Lib\Victron\VictronVRM\VictronVRM.csproj", "{FE05DF69-B5C7-4C2E-8FB9-7776441A7622}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VictronVRM", "Lib/Victron/VictronVRM/VictronVRM.csproj", "{FE05DF69-B5C7-4C2E-8FB9-7776441A7622}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ampt", "Lib\Devices\AMPT\Ampt.csproj", "{77AF3A64-2878-4150-BCD0-F16530783165}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ampt", "Lib/Devices/AMPT/Ampt.csproj", "{77AF3A64-2878-4150-BCD0-F16530783165}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Battery48TL", "Lib\Devices\Battery48TL\Battery48TL.csproj", "{1C3F443A-B339-4B08-80E6-8A84817FFEC9}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Battery48TL", "Lib/Devices/Battery48TL/Battery48TL.csproj", "{1C3F443A-B339-4B08-80E6-8A84817FFEC9}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmuMeter", "Lib\Devices\EmuMeter\EmuMeter.csproj", "{152A4168-F612-493C-BBEA-8EB26E6E2D34}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmuMeter", "Lib/Devices/EmuMeter/EmuMeter.csproj", "{152A4168-F612-493C-BBEA-8EB26E6E2D34}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "Lib\Utils\Utils.csproj", "{89A3E29C-4E57-47FE-A800-12AC68418264}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "Lib/Utils/Utils.csproj", "{89A3E29C-4E57-47FE-A800-12AC68418264}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Adam6060", "Lib\Devices\Adam6060\Adam6060.csproj", "{4AFDB799-E6A4-4DCA-8B6D-8C0F98398461}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Adam6060", "Lib/Devices/Adam6060/Adam6060.csproj", "{4AFDB799-E6A4-4DCA-8B6D-8C0F98398461}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Channels", "Lib\Channels\Channels.csproj", "{AF7E8DCA-8D48-498E-AB3D-208061B244DC}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Channels", "Lib/Channels/Channels.csproj", "{AF7E8DCA-8D48-498E-AB3D-208061B244DC}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Backend", "App\Backend\Backend.csproj", "{A56F58C2-B265-435B-A985-53B4D6F49B1A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Backend", "App/Backend/Backend.csproj", "{A56F58C2-B265-435B-A985-53B4D6F49B1A}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Units", "Lib\Units\Units.csproj", "{C04FB6DA-23C6-46BB-9B21-8F4FBA32FFF7}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Units", "Lib/Units/Units.csproj", "{C04FB6DA-23C6-46BB-9B21-8F4FBA32FFF7}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemControl", "Lib\Devices\Trumpf\SystemControl\SystemControl.csproj", "{B816BB44-E97E-4E02-B80A-BEDB5B923A96}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemControl", "Lib/Devices/Trumpf/SystemControl/SystemControl.csproj", "{B816BB44-E97E-4E02-B80A-BEDB5B923A96}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Meta", "Meta", "{AED84693-C389-44C9-B2C0-ACB560189CF2}"
ProjectSection(SolutionItems) = preProject
@@ -88,6 +87,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Doepke", "Lib\Devices\Doepk
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amax5070", "Lib\Devices\Amax5070\Amax5070.csproj", "{09E280B0-43D3-47BD-AF15-CF4FCDD24FE6}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SofarInverter", "Lib\Devices\SofarInverter\SofarInverter.csproj", "{2C7F3D89-402B-43CB-988E-8D2D853BEF44}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SchneiderMeterDriver", "App\SchneiderMeterDriver\SchneiderMeterDriver.csproj", "{2E7E7657-3A53-4B62-8927-FE9A082B81DE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Battery250UP", "Lib\Devices\Battery250UP\Battery250UP.csproj", "{F2967439-A590-4D5E-9208-1B973C83AA1C}"
@@ -108,6 +109,17 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SinexcelCommunication", "Ap
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sinexcel 12K TL", "Sinexcel 12K TL\Sinexcel 12K TL.csproj", "{28C16B43-E498-40DB-8ACF-D7F2A88A402F}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kaco92L3", "Lib\Devices\Kaco92L3\Kaco92L3.csproj", "{E60412AA-F88C-4CB7-AEFC-78427B1ADA13}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KacoCommunication", "App\KacoCommunication\KacoCommunication.csproj", "{0380E4B0-2A0C-4E3B-8536-499B72B23179}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PLVario2Meter", "Lib\Devices\PLVario2Meter\PLVario2Meter.csproj", "{D6D07FC5-2925-4B13-9F65-22123E07F8CC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GPIORaspberryPI4", "Lib\Devices\GPIORaspberryPI4\GPIORaspberryPI4.csproj", "{5E7A867E-D026-43B4-BDB9-240E4331CA23}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GpioTestingProject", "App\GpioTestingProject\GpioTestingProject.csproj", "{C6E3B901-3730-4B04-B821-85A6673C3D25}"
+EndProject
+
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -246,6 +258,10 @@ Global
{09E280B0-43D3-47BD-AF15-CF4FCDD24FE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{09E280B0-43D3-47BD-AF15-CF4FCDD24FE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09E280B0-43D3-47BD-AF15-CF4FCDD24FE6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2C7F3D89-402B-43CB-988E-8D2D853BEF44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2C7F3D89-402B-43CB-988E-8D2D853BEF44}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2C7F3D89-402B-43CB-988E-8D2D853BEF44}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2C7F3D89-402B-43CB-988E-8D2D853BEF44}.Release|Any CPU.Build.0 = Release|Any CPU
{2E7E7657-3A53-4B62-8927-FE9A082B81DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E7E7657-3A53-4B62-8927-FE9A082B81DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E7E7657-3A53-4B62-8927-FE9A082B81DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -286,6 +302,26 @@ Global
{28C16B43-E498-40DB-8ACF-D7F2A88A402F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{28C16B43-E498-40DB-8ACF-D7F2A88A402F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{28C16B43-E498-40DB-8ACF-D7F2A88A402F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E60412AA-F88C-4CB7-AEFC-78427B1ADA13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E60412AA-F88C-4CB7-AEFC-78427B1ADA13}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E60412AA-F88C-4CB7-AEFC-78427B1ADA13}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E60412AA-F88C-4CB7-AEFC-78427B1ADA13}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0380E4B0-2A0C-4E3B-8536-499B72B23179}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0380E4B0-2A0C-4E3B-8536-499B72B23179}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0380E4B0-2A0C-4E3B-8536-499B72B23179}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0380E4B0-2A0C-4E3B-8536-499B72B23179}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D6D07FC5-2925-4B13-9F65-22123E07F8CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D6D07FC5-2925-4B13-9F65-22123E07F8CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D6D07FC5-2925-4B13-9F65-22123E07F8CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D6D07FC5-2925-4B13-9F65-22123E07F8CC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5E7A867E-D026-43B4-BDB9-240E4331CA23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5E7A867E-D026-43B4-BDB9-240E4331CA23}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5E7A867E-D026-43B4-BDB9-240E4331CA23}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5E7A867E-D026-43B4-BDB9-240E4331CA23}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C6E3B901-3730-4B04-B821-85A6673C3D25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C6E3B901-3730-4B04-B821-85A6673C3D25}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C6E3B901-3730-4B04-B821-85A6673C3D25}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C6E3B901-3730-4B04-B821-85A6673C3D25}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{CF4834CB-91B7-4172-AC13-ECDA8613CD17} = {145597B4-3E30-45E6-9F72-4DD43194539A}
@@ -325,6 +361,7 @@ Global
{73B97F6E-2BDC-40DA-84A7-7FB0264387D6} = {AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854}
{C2B14CD4-1BCA-4933-96D9-92F40EACD2B9} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
{09E280B0-43D3-47BD-AF15-CF4FCDD24FE6} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
+ {2C7F3D89-402B-43CB-988E-8D2D853BEF44} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
{2E7E7657-3A53-4B62-8927-FE9A082B81DE} = {145597B4-3E30-45E6-9F72-4DD43194539A}
{F2967439-A590-4D5E-9208-1B973C83AA1C} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
{1045AC74-D4D8-4581-AAE3-575DF26060E6} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
@@ -335,5 +372,10 @@ Global
{6069D487-DBAB-4253-BFA1-CF994B84BE49} = {145597B4-3E30-45E6-9F72-4DD43194539A}
{93084D79-2977-47A1-9CAC-3E2DC6423F5B} = {145597B4-3E30-45E6-9F72-4DD43194539A}
{28C16B43-E498-40DB-8ACF-D7F2A88A402F} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
+ {E60412AA-F88C-4CB7-AEFC-78427B1ADA13} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
+ {0380E4B0-2A0C-4E3B-8536-499B72B23179} = {145597B4-3E30-45E6-9F72-4DD43194539A}
+ {D6D07FC5-2925-4B13-9F65-22123E07F8CC} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
+ {5E7A867E-D026-43B4-BDB9-240E4331CA23} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
+ {C6E3B901-3730-4B04-B821-85A6673C3D25} = {145597B4-3E30-45E6-9F72-4DD43194539A}
EndGlobalSection
EndGlobal
diff --git a/csharp/Lib/Devices/GPIORaspberryPI4/DigitalInput.cs b/csharp/Lib/Devices/GPIORaspberryPI4/DigitalInput.cs
new file mode 100644
index 000000000..26301fadd
--- /dev/null
+++ b/csharp/Lib/Devices/GPIORaspberryPI4/DigitalInput.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Device.Gpio;
+
+namespace GPIORaspberryPI4;
+
+public sealed class DigitalInput : IDigitalInput
+{
+ private readonly GpioController _gpio;
+ private readonly int _pin;
+ private readonly bool _activeLow;
+ private bool _disposed;
+
+ public int Pin => _pin;
+
+ public bool IsActive => Read();
+
+ public DigitalInput(int pin, bool pullUp = true, bool activeLow = true)
+ {
+ _pin = pin;
+ _activeLow = activeLow;
+
+ _gpio = new GpioController();
+
+ var mode = pullUp ? PinMode.InputPullUp : PinMode.Input;
+
+ _gpio.OpenPin(_pin, mode);
+ }
+
+ public bool Read()
+ {
+ ThrowIfDisposed();
+
+ var value = _gpio.Read(_pin);
+
+ return _activeLow
+ ? value == PinValue.Low
+ : value == PinValue.High;
+ }
+
+ private void ThrowIfDisposed()
+ {
+ if (_disposed)
+ throw new ObjectDisposedException(nameof(DigitalInput));
+ }
+
+ public void Dispose()
+ {
+ if (_disposed)
+ return;
+
+ if (_gpio.IsPinOpen(_pin))
+ _gpio.ClosePin(_pin);
+
+ _gpio.Dispose();
+ _disposed = true;
+ }
+}
\ No newline at end of file
diff --git a/csharp/Lib/Devices/GPIORaspberryPI4/GPIORaspberryPI4.csproj b/csharp/Lib/Devices/GPIORaspberryPI4/GPIORaspberryPI4.csproj
new file mode 100644
index 000000000..9b12551de
--- /dev/null
+++ b/csharp/Lib/Devices/GPIORaspberryPI4/GPIORaspberryPI4.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/csharp/Lib/Devices/GPIORaspberryPI4/IDigitalInput.cs b/csharp/Lib/Devices/GPIORaspberryPI4/IDigitalInput.cs
new file mode 100644
index 000000000..5102bfae2
--- /dev/null
+++ b/csharp/Lib/Devices/GPIORaspberryPI4/IDigitalInput.cs
@@ -0,0 +1,8 @@
+namespace GPIORaspberryPI4;
+
+public interface IDigitalInput : IDisposable
+{
+ int Pin { get; }
+ bool IsActive { get; }
+ bool Read();
+}
\ No newline at end of file
diff --git a/csharp/Lib/Devices/GPIORaspberryPI4/IRelayOutput.cs b/csharp/Lib/Devices/GPIORaspberryPI4/IRelayOutput.cs
new file mode 100644
index 000000000..351919cda
--- /dev/null
+++ b/csharp/Lib/Devices/GPIORaspberryPI4/IRelayOutput.cs
@@ -0,0 +1,9 @@
+namespace GPIORaspberryPI4;
+
+public interface IRelayOutput : IDisposable
+{
+ void On();
+ void Off();
+ void Set(bool on);
+ bool IsOn { get; }
+}
\ No newline at end of file
diff --git a/csharp/Lib/Devices/GPIORaspberryPI4/RelayOutput.cs b/csharp/Lib/Devices/GPIORaspberryPI4/RelayOutput.cs
new file mode 100644
index 000000000..e0c1e2b65
--- /dev/null
+++ b/csharp/Lib/Devices/GPIORaspberryPI4/RelayOutput.cs
@@ -0,0 +1,81 @@
+using System.Device.Gpio;
+
+namespace GPIORaspberryPI4;
+
+public sealed class RelayOutput : IRelayOutput
+{
+ private readonly GpioController _gpio;
+ private readonly int _pin;
+ private readonly bool _activeLow;
+ private bool _disposed;
+
+ public bool IsOn { get; private set; }
+
+ public RelayOutput(int pin, bool activeLow = false)
+ {
+ _pin = pin;
+ _activeLow = activeLow;
+
+ _gpio = new GpioController();
+ _gpio.OpenPin(_pin, PinMode.Output);
+
+ // Safe default state
+ WriteInternal(false);
+ }
+
+ public void On()
+ {
+ ThrowIfDisposed();
+ WriteInternal(true);
+ }
+
+ public void Off()
+ {
+ ThrowIfDisposed();
+ WriteInternal(false);
+ }
+
+ public void Set(bool on)
+ {
+ ThrowIfDisposed();
+ WriteInternal(on);
+ }
+
+ private void WriteInternal(bool on)
+ {
+ var pinValue = _activeLow
+ ? (on ? PinValue.Low : PinValue.High)
+ : (on ? PinValue.High : PinValue.Low);
+
+ _gpio.Write(_pin, pinValue);
+ IsOn = on;
+ }
+
+ private void ThrowIfDisposed()
+ {
+ if (_disposed)
+ throw new ObjectDisposedException(nameof(RelayOutput));
+ }
+
+ public void Dispose()
+ {
+ if (_disposed)
+ return;
+
+ try
+ {
+ // Fail-safe: relay OFF on dispose
+ WriteInternal(false);
+ }
+ catch
+ {
+ // Ignore cleanup errors
+ }
+
+ if (_gpio.IsPinOpen(_pin))
+ _gpio.ClosePin(_pin);
+
+ _gpio.Dispose();
+ _disposed = true;
+ }
+}
\ No newline at end of file