diff --git a/fhem/CHANGED b/fhem/CHANGED index 717d4e109..1202b1128 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,7 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - bugfix: 36_Vallox: Fixed Multireadings. Added Legacy Mapping. + added set commands - bugfix: 00_MQTT: topics and payload patch - bugfix: 73_GardenaSmartBridge: fix fetch token after rereadcfg - feature: 60_allergy: alternative data source for extended 5 day forecast diff --git a/fhem/FHEM/36_Vallox.pm b/fhem/FHEM/36_Vallox.pm index d801df66e..06b3229fb 100644 --- a/fhem/FHEM/36_Vallox.pm +++ b/fhem/FHEM/36_Vallox.pm @@ -5,13 +5,13 @@ # # @Author Skjall # @Created 21.07.2016 10:18:23 -# @Version 1.4.0 +# @Version 1.5.0 # # The modul reads and writes parameters via RS485 from and to a Vallox # ventilation bus. # # This module was made possible by Heinz from mysensors Community -# (https://forum.mysensors.org/user/heinz). His insights to the +# (https://forum.mysensors.org/user/heinz). His insights to the # Vallox bus were nessecary to make this script. - Thanks! # # This script is free software; you can redistribute it and/or modify @@ -53,7 +53,6 @@ my %Vallox_datatypes_base = ( "07" => "MultiPurpose1", "08" => "MultiPurpose2", - "29" => "FanSpeed", "2A" => "Humidity", "2B" => "CO2High", @@ -69,7 +68,7 @@ my %Vallox_datatypes_base = ( "34" => "TempInside", "35" => "TempIncoming", "36" => "LastSystemFault", - + "55" => "PostHeatingOnCounter", "56" => "PostHeatingOffTime", "57" => "PostHeatingTargetValue", @@ -82,10 +81,10 @@ my %Vallox_datatypes_base = ( "71" => "Flags6", "79" => "FireplaceBoosterCountdownMinutes", - + "8F" => "ResumeBus", "91" => "SuspendBusForCO2Communication", - + "A3" => "Select", "A4" => "HeatingSetPoint", "A5" => "FanSpeedMax", @@ -104,7 +103,7 @@ my %Vallox_datatypes_base = ( "B3" => "CO2SetPointUpper", "B4" => "CO2SetPointLower", "B5" => "Program2", - + "C0" => "Initial1", "C6" => "Initial2", "C7" => "Initial3", @@ -113,17 +112,16 @@ my %Vallox_datatypes_base = ( ); my %Vallox_datatypesReverse_base = reverse %Vallox_datatypes_base; - my %Vallox_datatypes_legacy1 = ( - "49" => "Legacy49", # Unknown legacy Reading - "4A" => "Legacy4A", # Unknown legacy Reading - "4C" => "Legacy4C", # Unknown legacy Reading - "53" => "Legacy53", # Unknown legacy Reading - "54" => "Legacy54", # Unknown legacy Reading - "58" => "Legacy58", # Unknown legacy Reading - "5A" => "Legacy5A", # Unknown legacy Reading - "5B" => "Legacy5B", # Unknown legacy Reading - "5C" => "Legacy5C", # Unknown legacy Reading + "49" => "Legacy49", # Unknown legacy Reading + "4A" => "Legacy4A", # Unknown legacy Reading + "4C" => "Legacy4C", # Unknown legacy Reading + "53" => "Legacy53", # Unknown legacy Reading + "54" => "Legacy54", # Unknown legacy Reading + "58" => "TempOutside", + "5A" => "TempInside", + "5B" => "TempIncoming", + "5C" => "TempExhaust", ); my %Vallox_datatypesReverse_legacy1 = reverse %Vallox_datatypes_legacy1; @@ -131,14 +129,14 @@ my %Vallox_datatypesReverse_legacy1 = reverse %Vallox_datatypes_legacy1; # Mapping of the fan speeds ################################## my %Vallox_levelTable = ( -"01" => "1", -"03" => "2", -"07" => "3", -"0F" => "4", -"1F" => "5", -"3F" => "6", -"7F" => "7", -"FF" => "8", + "01" => "1", + "03" => "2", + "07" => "3", + "0F" => "4", + "1F" => "5", + "3F" => "6", + "7F" => "7", + "FF" => "8", ); my %Vallox_levelTableReverse = reverse %Vallox_levelTable; @@ -146,57 +144,370 @@ my %Vallox_levelTableReverse = reverse %Vallox_levelTable; # Mapping of the temperatures ################################## my %Vallox_temperatureTable = ( -"00" => "-74", "01" => "-70", "02" => "-66", "03" => "-62", "04" => "-59", "05" => "-56", "06" => "-54", "07" => "-52", -"08" => "-50", "09" => "-48", "0A" => "-47", "0B" => "-46", "0C" => "-44", "0D" => "-43", "0E" => "-42", "0F" => "-41", -"10" => "-40", "11" => "-39", "12" => "-38", "13" => "-37", "14" => "-36", "15" => "-35", "16" => "-34", "17" => "-33", -"18" => "-33", "19" => "-32", "1A" => "-31", "1B" => "-30", "1C" => "-30", "1D" => "-29", "1E" => "-28", "1F" => "-28", -"20" => "-27", "21" => "-27", "22" => "-26", "23" => "-25", "24" => "-25", "25" => "-24", "26" => "-24", "27" => "-23", -"28" => "-23", "29" => "-22", "2A" => "-22", "2B" => "-21", "2C" => "-21", "2D" => "-20", "2E" => "-20", "2F" => "-19", -"30" => "-19", "31" => "-19", "32" => "-18", "33" => "-18", "34" => "-17", "35" => "-17", "36" => "-16", "37" => "-16", -"38" => "-16", "39" => "-15", "3A" => "-15", "3B" => "-14", "3C" => "-14", "3D" => "-14", "3E" => "-13", "3F" => "-13", -"40" => "-12", "41" => "-12", "42" => "-12", "43" => "-11", "44" => "-11", "45" => "-11", "46" => "-10", "47" => "-10", -"48" => "-9", "49" => "-9", "4A" => "-9", "4B" => "-8", "4C" => "-8", "4D" => "-8", "4E" => "-7", "4F" => "-7", -"50" => "-7", "51" => "-6", "52" => "-6", "53" => "-6", "54" => "-5", "55" => "-5", "56" => "-5", "57" => "-4", -"58" => "-4", "59" => "-4", "5A" => "-3", "5B" => "-3", "5C" => "-3", "5D" => "-2", "5E" => "-2", "5F" => "-2", -"60" => "-1", "61" => "-1", "62" => "-1", "63" => "-1", "64" => "0", "65" => "0", "66" => "0", "67" => "1", -"68" => "1", "69" => "1", "6A" => "2", "6B" => "2", "6C" => "2", "6D" => "3", "6E" => "3", "6F" => "3", -"70" => "4", "71" => "4", "72" => "4", "73" => "5", "74" => "5", "75" => "5", "76" => "5", "77" => "6", -"78" => "6", "79" => "6", "7A" => "7", "7B" => "7", "7C" => "7", "7D" => "8", "7E" => "8", "7F" => "8", -"80" => "9", "81" => "9", "82" => "9", "83" => "10", "84" => "10", "85" => "10", "86" => "11", "87" => "11", -"88" => "11", "89" => "12", "8A" => "12", "8B" => "12", "8C" => "13", "8D" => "13", "8E" => "13", "8F" => "14", -"90" => "14", "91" => "14", "92" => "15", "93" => "15", "94" => "15", "95" => "16", "96" => "16", "97" => "16", -"98" => "17", "99" => "17", "9A" => "18", "9B" => "18", "9C" => "18", "9D" => "19", "9E" => "19", "9F" => "19", -"A0" => "20", "A1" => "20", "A2" => "21", "A3" => "21", "A4" => "21", "A5" => "22", "A6" => "22", "A7" => "22", -"A8" => "23", "A9" => "23", "AA" => "24", "AB" => "24", "AC" => "24", "AD" => "25", "AE" => "25", "AF" => "26", -"B0" => "26", "B1" => "27", "B2" => "27", "B3" => "27", "B4" => "28", "B5" => "28", "B6" => "29", "B7" => "29", -"B8" => "30", "B9" => "30", "BA" => "31", "BB" => "31", "BC" => "32", "BD" => "32", "BE" => "33", "BF" => "33", -"C0" => "34", "C1" => "34", "C2" => "35", "C3" => "35", "C4" => "36", "C5" => "36", "C6" => "37", "C7" => "37", -"C8" => "38", "C9" => "38", "CA" => "39", "CB" => "40", "CC" => "40", "CD" => "41", "CE" => "41", "CF" => "42", -"D0" => "43", "D1" => "43", "D2" => "44", "D3" => "45", "D4" => "45", "D5" => "46", "D6" => "47", "D7" => "48", -"D8" => "49", "D9" => "49", "DA" => "50", "DB" => "51", "DC" => "52", "DD" => "53", "DE" => "53", "DF" => "54", -"E0" => "55", "E1" => "56", "E2" => "57", "E3" => "59", "E4" => "60", "E5" => "61", "E6" => "62", "E7" => "63", -"E8" => "65", "E9" => "66", "EA" => "68", "EB" => "69", "EC" => "71", "ED" => "73", "EE" => "75", "EF" => "77", -"F0" => "79", "F1" => "81", "F2" => "82", "F3" => "86", "F4" => "90", "F5" => "93", "F6" => "97", "F7" => "100", -"F8" => "100", "F9" => "100", "FA" => "100", "FB" => "100", "FC" => "100", "FD" => "100", "FE" => "100", "FF" => "100" + "00" => "-74", + "01" => "-70", + "02" => "-66", + "03" => "-62", + "04" => "-59", + "05" => "-56", + "06" => "-54", + "07" => "-52", + "08" => "-50", + "09" => "-48", + "0A" => "-47", + "0B" => "-46", + "0C" => "-44", + "0D" => "-43", + "0E" => "-42", + "0F" => "-41", + "10" => "-40", + "11" => "-39", + "12" => "-38", + "13" => "-37", + "14" => "-36", + "15" => "-35", + "16" => "-34", + "17" => "-33", + "18" => "-33", + "19" => "-32", + "1A" => "-31", + "1B" => "-30", + "1C" => "-30", + "1D" => "-29", + "1E" => "-28", + "1F" => "-28", + "20" => "-27", + "21" => "-27", + "22" => "-26", + "23" => "-25", + "24" => "-25", + "25" => "-24", + "26" => "-24", + "27" => "-23", + "28" => "-23", + "29" => "-22", + "2A" => "-22", + "2B" => "-21", + "2C" => "-21", + "2D" => "-20", + "2E" => "-20", + "2F" => "-19", + "30" => "-19", + "31" => "-19", + "32" => "-18", + "33" => "-18", + "34" => "-17", + "35" => "-17", + "36" => "-16", + "37" => "-16", + "38" => "-16", + "39" => "-15", + "3A" => "-15", + "3B" => "-14", + "3C" => "-14", + "3D" => "-14", + "3E" => "-13", + "3F" => "-13", + "40" => "-12", + "41" => "-12", + "42" => "-12", + "43" => "-11", + "44" => "-11", + "45" => "-11", + "46" => "-10", + "47" => "-10", + "48" => "-9", + "49" => "-9", + "4A" => "-9", + "4B" => "-8", + "4C" => "-8", + "4D" => "-8", + "4E" => "-7", + "4F" => "-7", + "50" => "-7", + "51" => "-6", + "52" => "-6", + "53" => "-6", + "54" => "-5", + "55" => "-5", + "56" => "-5", + "57" => "-4", + "58" => "-4", + "59" => "-4", + "5A" => "-3", + "5B" => "-3", + "5C" => "-3", + "5D" => "-2", + "5E" => "-2", + "5F" => "-2", + "60" => "-1", + "61" => "-1", + "62" => "-1", + "63" => "-1", + "64" => "0", + "65" => "0", + "66" => "0", + "67" => "1", + "68" => "1", + "69" => "1", + "6A" => "2", + "6B" => "2", + "6C" => "2", + "6D" => "3", + "6E" => "3", + "6F" => "3", + "70" => "4", + "71" => "4", + "72" => "4", + "73" => "5", + "74" => "5", + "75" => "5", + "76" => "5", + "77" => "6", + "78" => "6", + "79" => "6", + "7A" => "7", + "7B" => "7", + "7C" => "7", + "7D" => "8", + "7E" => "8", + "7F" => "8", + "80" => "9", + "81" => "9", + "82" => "9", + "83" => "10", + "84" => "10", + "85" => "10", + "86" => "11", + "87" => "11", + "88" => "11", + "89" => "12", + "8A" => "12", + "8B" => "12", + "8C" => "13", + "8D" => "13", + "8E" => "13", + "8F" => "14", + "90" => "14", + "91" => "14", + "92" => "15", + "93" => "15", + "94" => "15", + "95" => "16", + "96" => "16", + "97" => "16", + "98" => "17", + "99" => "17", + "9A" => "18", + "9B" => "18", + "9C" => "18", + "9D" => "19", + "9E" => "19", + "9F" => "19", + "A0" => "20", + "A1" => "20", + "A2" => "21", + "A3" => "21", + "A4" => "21", + "A5" => "22", + "A6" => "22", + "A7" => "22", + "A8" => "23", + "A9" => "23", + "AA" => "24", + "AB" => "24", + "AC" => "24", + "AD" => "25", + "AE" => "25", + "AF" => "26", + "B0" => "26", + "B1" => "27", + "B2" => "27", + "B3" => "27", + "B4" => "28", + "B5" => "28", + "B6" => "29", + "B7" => "29", + "B8" => "30", + "B9" => "30", + "BA" => "31", + "BB" => "31", + "BC" => "32", + "BD" => "32", + "BE" => "33", + "BF" => "33", + "C0" => "34", + "C1" => "34", + "C2" => "35", + "C3" => "35", + "C4" => "36", + "C5" => "36", + "C6" => "37", + "C7" => "37", + "C8" => "38", + "C9" => "38", + "CA" => "39", + "CB" => "40", + "CC" => "40", + "CD" => "41", + "CE" => "41", + "CF" => "42", + "D0" => "43", + "D1" => "43", + "D2" => "44", + "D3" => "45", + "D4" => "45", + "D5" => "46", + "D6" => "47", + "D7" => "48", + "D8" => "49", + "D9" => "49", + "DA" => "50", + "DB" => "51", + "DC" => "52", + "DD" => "53", + "DE" => "53", + "DF" => "54", + "E0" => "55", + "E1" => "56", + "E2" => "57", + "E3" => "59", + "E4" => "60", + "E5" => "61", + "E6" => "62", + "E7" => "63", + "E8" => "65", + "E9" => "66", + "EA" => "68", + "EB" => "69", + "EC" => "71", + "ED" => "73", + "EE" => "75", + "EF" => "77", + "F0" => "79", + "F1" => "81", + "F2" => "82", + "F3" => "86", + "F4" => "90", + "F5" => "93", + "F6" => "97", + "F7" => "100", + "F8" => "100", + "F9" => "100", + "FA" => "100", + "FB" => "100", + "FC" => "100", + "FD" => "100", + "FE" => "100", + "FF" => "100" ); my %Vallox_temperatureTableReverse = reverse %Vallox_temperatureTable; - ################################## # Mapping of the percentages (eg humidity) ################################## my %Vallox_percentageTable = ( -"34" => "0", "36" => "1", "38" => "2", "3A" => "3", "3C" => "4", "3E" => "5", "40" => "6", "42" => "7", "44" => "8", "46" => "9", -"48" => "10", "4A" => "11", "4C" => "12", "4E" => "13", "50" => "14", "52" => "15", "54" => "16", "56" => "17", "58" => "18", "5A" => "19", -"5C" => "20", "5E" => "21", "60" => "22", "62" => "23", "64" => "24", "66" => "25", "68" => "26", "6A" => "27", "6C" => "28", "6E" => "29", -"70" => "30", "72" => "31", "74" => "32", "76" => "33", "78" => "34", "7A" => "35", "7C" => "36", "7E" => "37", "80" => "38", "82" => "39", -"84" => "40", "86" => "41", "88" => "42", "8A" => "43", "8C" => "44", "8E" => "45", "90" => "46", "92" => "47", "94" => "48", "96" => "49", -"98" => "50", "9A" => "51", "9C" => "52", "9E" => "53", "A0" => "54", "A2" => "55", "A4" => "56", "A6" => "57", "A8" => "58", "AA" => "59", -"AC" => "60", "AE" => "61", "B0" => "62", "B2" => "63", "B4" => "64", "B6" => "65", "B8" => "66", "BA" => "67", "BC" => "68", "BE" => "69", -"C0" => "70", "C2" => "71", "C4" => "72", "C6" => "73", "C8" => "74", "CA" => "75", "CC" => "76", "CE" => "77", "D0" => "78", "D2" => "79", -"D4" => "80", "D6" => "81", "D8" => "82", "DA" => "83", "DC" => "84", "DE" => "85", "E0" => "86", "E2" => "87", "E4" => "88", "E6" => "89", -"E8" => "90", "EA" => "91", "EC" => "92", "EE" => "93", "F0" => "94", "F2" => "95", "F4" => "96", "F6" => "97", "F8" => "98", "FA" => "99", -"FC" => "100" + "34" => "0", + "36" => "1", + "38" => "2", + "3A" => "3", + "3C" => "4", + "3E" => "5", + "40" => "6", + "42" => "7", + "44" => "8", + "46" => "9", + "48" => "10", + "4A" => "11", + "4C" => "12", + "4E" => "13", + "50" => "14", + "52" => "15", + "54" => "16", + "56" => "17", + "58" => "18", + "5A" => "19", + "5C" => "20", + "5E" => "21", + "60" => "22", + "62" => "23", + "64" => "24", + "66" => "25", + "68" => "26", + "6A" => "27", + "6C" => "28", + "6E" => "29", + "70" => "30", + "72" => "31", + "74" => "32", + "76" => "33", + "78" => "34", + "7A" => "35", + "7C" => "36", + "7E" => "37", + "80" => "38", + "82" => "39", + "84" => "40", + "86" => "41", + "88" => "42", + "8A" => "43", + "8C" => "44", + "8E" => "45", + "90" => "46", + "92" => "47", + "94" => "48", + "96" => "49", + "98" => "50", + "9A" => "51", + "9C" => "52", + "9E" => "53", + "A0" => "54", + "A2" => "55", + "A4" => "56", + "A6" => "57", + "A8" => "58", + "AA" => "59", + "AC" => "60", + "AE" => "61", + "B0" => "62", + "B2" => "63", + "B4" => "64", + "B6" => "65", + "B8" => "66", + "BA" => "67", + "BC" => "68", + "BE" => "69", + "C0" => "70", + "C2" => "71", + "C4" => "72", + "C6" => "73", + "C8" => "74", + "CA" => "75", + "CC" => "76", + "CE" => "77", + "D0" => "78", + "D2" => "79", + "D4" => "80", + "D6" => "81", + "D8" => "82", + "DA" => "83", + "DC" => "84", + "DE" => "85", + "E0" => "86", + "E2" => "87", + "E4" => "88", + "E6" => "89", + "E8" => "90", + "EA" => "91", + "EC" => "92", + "EE" => "93", + "F0" => "94", + "F2" => "95", + "F4" => "96", + "F6" => "97", + "F8" => "98", + "FA" => "99", + "FC" => "100" ); my %Vallox_percentageTableReverse = reverse %Vallox_percentageTable; @@ -204,13 +515,13 @@ my %Vallox_percentageTableReverse = reverse %Vallox_percentageTable; # Mapping of the faults ################################## my %Vallox_faultTable = ( -"00" => "No fault stored", -"05" => "Supply air temperature sensor fault", -"06" => "Carbon dioxide alarm", -"07" => "Outdoor air sensor fault", -"08" => "Extract air sensor fault", -"09" => "Water radiator danger of freezing", -"0A" => "Exhaust air sensor fault", + "00" => "No fault stored", + "05" => "Supply air temperature sensor fault", + "06" => "Carbon dioxide alarm", + "07" => "Outdoor air sensor fault", + "08" => "Extract air sensor fault", + "09" => "Water radiator danger of freezing", + "0A" => "Exhaust air sensor fault", ); my %Vallox_faultTableReverse = reverse %Vallox_faultTable; @@ -219,74 +530,71 @@ my %Vallox_faultTableReverse = reverse %Vallox_faultTable; # TODO: Find s.th. more elegant for all MR ################################## my %Vallox_multiReadingTable_realcmd = ( -"SupplyFan" => "MultiPurpose2", -"ExhaustFan" => "MultiPurpose2", -"CO2HigherSpeedRequest" => "Flags2", -"CO2LowerRatePublicInvitation" => "Flags2", -"HumidityLowerRatePublicInvitation" => "Flags2", -"SwitchLowerSpeedRequest" => "Flags2", -"CO2Alarm" => "Flags2", -"FrostAlarmSensor" => "Flags2", -"FrostAlarmWaterRadiator" => "Flags4", -"MasterSlaveSelection" => "Flags4", -"PreHeatingStatus" => "Flags5", -"FireplaceSwitchActivation" => "Flags6", -"PowerState" => "Select", -"CO2AdjustState" => "Select", -"RHAdjustState" => "Select", -"HeatingState" => "Select", -"AutomaticHumidityBasicLevelSeekerState" => "Program", -"BoostSwitchMode" => "Program", -"RadiatorType" => "Program", -"CascadeAdjust" => "Program", -"MaxSpeedLimitFunction" => "Program2", + "SupplyFan" => "MultiPurpose2", + "ExhaustFan" => "MultiPurpose2", + "CO2HigherSpeedRequest" => "Flags2", + "CO2LowerRatePublicInvitation" => "Flags2", + "HumidityLowerRatePublicInvitation" => "Flags2", + "SwitchLowerSpeedRequest" => "Flags2", + "CO2Alarm" => "Flags2", + "FrostAlarmSensor" => "Flags2", + "FrostAlarmWaterRadiator" => "Flags4", + "MasterSlaveSelection" => "Flags4", + "PreHeatingStatus" => "Flags5", + "FireplaceSwitchActivation" => "Flags6", + "PowerState" => "Select", + "CO2AdjustState" => "Select", + "RHAdjustState" => "Select", + "HeatingState" => "Select", + "ServiceReminderIndicator" => "Select", + "AutomaticHumidityBasicLevelSeekerState" => "Program", + "BoostSwitchMode" => "Program", + "RadiatorType" => "Program", + "CascadeAdjust" => "Program", + "MaxSpeedLimitFunction" => "Program2", ); my %Vallox_multiReadingTable_digit = ( -"SupplyFan" => 3, -"ExhaustFan" => 5, -"CO2HigherSpeedRequest" => 0, -"CO2LowerRatePublicInvitation" => 1, -"HumidityLowerRatePublicInvitation" => 2, -"SwitchLowerSpeedRequest" => 3, -"CO2Alarm" => 6, -"FrostAlarmSensor" => 7, -"FrostAlarmWaterRadiator" => 4, -"MasterSlaveSelection" => 7, -"PreHeatingStatus" => 7, -"FireplaceSwitchActivation" => 5, -"PowerState" => 0, -"CO2AdjustState" => 1, -"RHAdjustState" => 2, -"HeatingState" => 3, -"AutomaticHumidityBasicLevelSeekerState" => 4, -"BoostSwitchMode" => 5, -"RadiatorType" => 6, -"CascadeAdjust" => 7, -"MaxSpeedLimitFunction" => 0, + "SupplyFan" => 3, + "ExhaustFan" => 5, + "CO2HigherSpeedRequest" => 0, + "CO2LowerRatePublicInvitation" => 1, + "HumidityLowerRatePublicInvitation" => 2, + "SwitchLowerSpeedRequest" => 3, + "CO2Alarm" => 6, + "FrostAlarmSensor" => 7, + "FrostAlarmWaterRadiator" => 4, + "MasterSlaveSelection" => 7, + "PreHeatingStatus" => 7, + "FireplaceSwitchActivation" => 5, + "PowerState" => 0, + "CO2AdjustState" => 1, + "RHAdjustState" => 2, + "HeatingState" => 3, + "ServiceReminderIndicator" => 7, + "AutomaticHumidityBasicLevelSeekerState" => 4, + "BoostSwitchMode" => 5, + "RadiatorType" => 6, + "CascadeAdjust" => 7, + "MaxSpeedLimitFunction" => 0, ); - ################################## # Initialize Buffer fillings ################################## -my $bufferRead = "00"; +my $bufferRead = "00"; my $bufferDevIO = "00"; my $bufferDebug = "--"; ################################## # basic get commands ################################## -my %Vallox_gets = ( - "raw" => "raw" -); +my %Vallox_gets = ( "raw" => "raw" ); ################################## # basic set commands ################################## -my %Vallox_sets = ( - "raw" => "raw" -); +my %Vallox_sets = ( "raw" => "raw" ); ############################################## # Custom Functions @@ -295,79 +603,106 @@ my %Vallox_sets = ( ################################## # Create a valid message to send ################################## -sub Vallox_CreateMsg ($@) -{ - my ($hash, $readingIdentifier) = @_; - - my $domain = hex "0x".AttrVal($hash->{NAME}, "ValloxIDDomain", "01"); # Domain (1 by default) - my $sender = hex "0x".AttrVal($hash->{NAME}, "ValloxIDFHEM", "2F"); # ID of this FHEM - my $receiver = hex "0x".AttrVal($hash->{NAME}, "ValloxIDCentral", "11"); # ID of the central - - my $datatype = hex "0x".$readingIdentifier; - my $checksum = ($domain + $sender + $receiver + $datatype) % 0x100; - - my $msg = lc(sprintf("%02x", $domain).sprintf("%02x", $sender).sprintf("%02x", $receiver)."00".sprintf("%02x", $datatype).sprintf("%02x", $checksum)); - - return $msg; +sub Vallox_CreateMsg ($@) { + my ( $hash, $readingIdentifier ) = @_; + + my $domain = hex "0x" + . AttrVal( $hash->{NAME}, "ValloxIDDomain", "01" ) + ; # Domain (1 by default) + my $sender = hex "0x" + . AttrVal( $hash->{NAME}, "ValloxIDFHEM", "2F" ); # ID of this FHEM + my $receiver = hex "0x" + . AttrVal( $hash->{NAME}, "ValloxIDCentral", "11" ); # ID of the central + + my $datatype = hex "0x" . $readingIdentifier; + my $checksum = ( $domain + $sender + $receiver + $datatype ) % 0x100; + + my $msg = + lc( + sprintf( "%02x", $domain ) + . sprintf( "%02x", $sender ) + . sprintf( "%02x", $receiver ) . "00" + . sprintf( "%02x", $datatype ) + . sprintf( "%02x", $checksum ) ); + + return $msg; } ############################################## # Check if a message is valid ############################################## -sub Vallox_ValidateStream ($@) -{ - my ($hash, @a) = @_; +sub Vallox_ValidateStream ($@) { + my ( $hash, @a ) = @_; my $name = shift @a; - - return undef if (length($bufferRead) < 12); - - my $domain = hex "0x".substr($bufferRead,0,2); - my $sender = hex "0x".substr($bufferRead,2,2); - my $receiver = hex "0x".substr($bufferRead,4,2); - my $data_1 = hex "0x".substr($bufferRead,6,2); - my $data_2 = hex "0x".substr($bufferRead,8,2); - - my $checksum = ($domain + $sender + $receiver + $data_1 + $data_2) % 0x100; - - #++$hash->{"CheckCount"}; - - if ( - lc($domain) eq 01 && - lc(sprintf("%02x", $domain).sprintf("%02x", $sender).sprintf("%02x", $receiver).sprintf("%02x", $data_1).sprintf("%02x", $data_2).sprintf("%02x", $checksum)) eq lc($bufferRead) - ) { - #Log3 ($name, 5, "Vallox: Debug: DO ".$domain." - SE ".$sender." - RE ".$receiver." - D1 ".$data_1." - D2 ".$data_2." - CS ".$checksum." NE ".$bufferRead); - - #++$hash->{"MessageCount"}; - #$hash->{"BufferDatagramRatio"} = "1 : ".$hash->{"CheckCount"} / $hash->{"MessageCount"}; - - - if (( - ( - $sender >= 17 && - $sender <= 31 - ) || ( - $sender >= 33 && - $sender <= 47 - ) - ) && ( - ( - $receiver >= 16 && - $receiver <= 31 - ) || ( - $receiver >= 32 && - $receiver <= 47 - ) - )) { - return 1; - } else { - - ++$hash->{"ErrorCount"}; - return 2; - } - } else { - Log3 ($name, 4, "Vallox: Debug: DO ".$domain." - SE ".$sender." - RE ".$receiver." - D1 ".$data_1." - D2 ".$data_2." - CS ".$checksum." NE ".$bufferRead); - return 0; - } + + return undef if ( length($bufferRead) < 12 ); + + my $domain = hex "0x" . substr( $bufferRead, 0, 2 ); + my $sender = hex "0x" . substr( $bufferRead, 2, 2 ); + my $receiver = hex "0x" . substr( $bufferRead, 4, 2 ); + my $data_1 = hex "0x" . substr( $bufferRead, 6, 2 ); + my $data_2 = hex "0x" . substr( $bufferRead, 8, 2 ); + + my $checksum = + ( $domain + $sender + $receiver + $data_1 + $data_2 ) % 0x100; + + #++$hash->{"CheckCount"}; + + if ( + lc($domain) eq 01 + && lc( + sprintf( "%02x", $domain ) + . sprintf( "%02x", $sender ) + . sprintf( "%02x", $receiver ) + . sprintf( "%02x", $data_1 ) + . sprintf( "%02x", $data_2 ) + . sprintf( "%02x", $checksum ) + ) eq lc($bufferRead) + ) + { + +#Log3 ($name, 5, "Vallox: Debug: DO ".$domain." - SE ".$sender." - RE ".$receiver." - D1 ".$data_1." - D2 ".$data_2." - CS ".$checksum." NE ".$bufferRead); + +#++$hash->{"MessageCount"}; +#$hash->{"BufferDatagramRatio"} = "1 : ".$hash->{"CheckCount"} / $hash->{"MessageCount"}; + + if ( + ( + ( $sender >= 17 && $sender <= 31 ) || ( $sender >= 33 + && $sender <= 47 ) + ) + && ( + ( $receiver >= 16 && $receiver <= 31 ) + || ( $receiver >= 32 + && $receiver <= 47 ) + ) + ) + { + return 1; + } + else { + + ++$hash->{"ErrorCount"}; + return 2; + } + } + else { + Log3( $name, 4, + "Vallox: Debug: DO " + . $domain + . " - SE " + . $sender + . " - RE " + . $receiver + . " - D1 " + . $data_1 + . " - D2 " + . $data_2 + . " - CS " + . $checksum . " NE " + . $bufferRead ); + return 0; + } } ############################################## @@ -375,399 +710,689 @@ sub Vallox_ValidateStream ($@) # (bitnumber = 0 (rightest) - 7 (leftest)!) ############################################## sub Vallox_ReplaceBit ($@) { - my ($hash, $bitstring, $bitnumber, $value) = @_; - - return substr($bitstring,0,8-$bitnumber-1).$value.substr($bitstring,8-$bitnumber,$bitnumber); + my ( $hash, $bitstring, $bitnumber, $value ) = @_; + + return + substr( $bitstring, 0, 8 - $bitnumber - 1 ) + . $value + . substr( $bitstring, 8 - $bitnumber, $bitnumber ); } ############################################## # Update reading bulk for binary reading ############################################## sub Vallox_ReadingsBulkUpdateMultiReading($@) { - my ($hash, $rawReadingType, $readingname, $bitnumber,) = @_; - - readingsBulkUpdate($hash, $readingname, substr($hash->{"MR_".$Vallox_datatypes{$rawReadingType}},8-$bitnumber-1,1)); # if (ReadingsVal($hash->{NAME},$readingname,"unknown") ne substr($hash->{"MR_".$Vallox_datatypes{$rawReadingType}},8-$bitnumber-1,1)); - return; - + my ( $hash, $rawReadingType, $readingname, $bitnumber, ) = @_; + + readingsBulkUpdate( + $hash, + $readingname, + substr( + $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} }, + 8 - $bitnumber - 1, 1 + ) + ) + ; # if (ReadingsVal($hash->{NAME},$readingname,"unknown") ne substr($hash->{"MR_".$Vallox_datatypes{$rawReadingType}},8-$bitnumber-1,1)); + return; + } ############################################## # Interpret datagram and handle it ############################################## sub Vallox_InterpretAndUpdate(@) { - - my ($hash,$datagram) = @_; - + + my ( $hash, $datagram ) = @_; + my $name = $hash->{NAME}; - + my $rawReadingType; my $rawReadingValue; my $rawReadingChecksum; - my $singlereading = 1; + my $singlereading = 1; my $fineReadingValue = 1; - - $datagram = uc($datagram); - - # get the type of the datagram - $rawReadingType = substr($datagram,6,2); - - # get the value of the datagram - $rawReadingValue = substr($datagram,8,2); - - # get the value of the datagram - $rawReadingChecksum = substr($datagram,10,2); - if ($rawReadingType ne "00") { + $datagram = uc($datagram); - # Decoding for the final readings. - # - rawReading... is the original information from the datagram - # - fineReading... is the human readable information - - # Starting with the "One information in one datagram"-Section - - # Convert FanSpeeds by the Vallox_levelTable - if ($rawReadingType eq "29" || $rawReadingType eq "A5" || $rawReadingType eq "A9") { - $fineReadingValue = $Vallox_levelTable{$rawReadingValue}; - Log3 ($name, 4, "Vallox: Incoming Status-Info (FanSpeed): $datagram (Level $fineReadingValue)"); - - # Convert Temperatures by the Vallox_temperatureTable - } elsif ($rawReadingType eq "32" || $rawReadingType eq "33" || $rawReadingType eq "34" || $rawReadingType eq "35" || $rawReadingType eq "A4" || $rawReadingType eq "A7" || $rawReadingType eq "A8" || $rawReadingType eq "AF") { - - if ( $rawReadingType eq "A4" && $hash->{BusVersion} eq "1") { - $fineReadingValue = $Vallox_levelTable{$rawReadingValue}; - - Log3 ($name, 4, "Vallox: Incoming Status-Info (HeatingSetPoint): $datagram (Level $fineReadingValue)"); - return; - } else { - $fineReadingValue = $Vallox_temperatureTable{$rawReadingValue}; - } - - if (($rawReadingType eq "32" || $rawReadingType eq "33" || $rawReadingType eq "34" || $rawReadingType eq "35") && $fineReadingValue < -40) { - Log3 ($name, 4, "Vallox: Incoming Status-Info (Temperature) invalid: $datagram ($fineReadingValue deg.)"); - return; - } - Log3 ($name, 4, "Vallox: Incoming Status-Info (Temperature): $datagram ($fineReadingValue deg.)"); - - # Convert Percentages by the Vallox_percentageTable - } elsif ($rawReadingType eq "AE") { - $fineReadingValue = $Vallox_percentageTable{$rawReadingValue}; - Log3 ($name, 4, "Vallox: Incoming Status-Info (Percentage): $datagram ($fineReadingValue pct.)"); - - # Convert Faults by the Vallox_faultTable - } elsif ($rawReadingType eq "36") { - $fineReadingValue = $Vallox_faultTable{$rawReadingValue}; - Log3 ($name, 4, "Vallox: Incoming Status-Info (Fault): $datagram ($fineReadingValue)"); - - # Convert Decimal Values - } elsif ($rawReadingType eq "2B" || $rawReadingType eq "2C" || $rawReadingType eq "2E" || $rawReadingType eq "57" || $rawReadingType eq "A6" || $rawReadingType eq "79" || $rawReadingType eq "8F" || $rawReadingType eq "91" || $rawReadingType eq "AB" || $rawReadingType eq "B0" || $rawReadingType eq "B1" || $rawReadingType eq "B3" || $rawReadingType eq "B4") { - $fineReadingValue = sprintf("%d", hex "0x".$rawReadingValue); - Log3 ($name, 4, "Vallox: Incoming Status-Info (Decimal): $datagram ($fineReadingValue)"); - - # Convert PostHeating Time Values - } elsif ($rawReadingType eq "55" || $rawReadingType eq "56") { - $fineReadingValue = sprintf("%d", hex "0x".$rawReadingValue)/2.5; - Log3 ($name, 4, "Vallox: Incoming Status-Info (PostHeatingCounter): $datagram ($fineReadingValue)"); - - # Convert CellDefrostingSetpointTemperature Values - } elsif ($rawReadingType eq "B2") { - $fineReadingValue = sprintf("%d", hex "0x".$rawReadingValue)/3; - Log3 ($name, 4, "Vallox: Incoming Status-Info (CellDefrostingSetpointTemperature): $datagram ($fineReadingValue)"); - - # Convert measured humidity by formula (if it is negative then you don't have a humidity sensor) - } elsif ($rawReadingType eq "2A" || $rawReadingType eq "2F" || $rawReadingType eq "30") { - $fineReadingValue = (sprintf("%d", hex "0x".$rawReadingValue)-51)/2.04; - - # Negative Humidity impossible: No Sensor attatched - if ($fineReadingValue < 0) { - Log3 ($name, 4, "Vallox: Incoming Status-Info (Humidity) invalid: $datagram ($fineReadingValue Perc. rH)"); - return; - } - - Log3 ($name, 4, "Vallox: Incoming Status-Info (Humidity): $datagram ($fineReadingValue pct. rH)"); - - # Starting with the "Up to eight informations in one datagram"-Section - # Disabled lines are unused. - - # FanSpeed-Relays - } elsif ($rawReadingType eq "06") { - - $hash->{"MR_".$Vallox_datatypes{$rawReadingType}} = sprintf('%08b', hex("0x".$rawReadingValue)); - - $singlereading = 0; - readingsBeginUpdate($hash); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "Speed1", 0); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "Speed2", 1); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "Speed3", 2); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "Speed4", 3); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "Speed5", 4); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "Speed6", 5); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "Speed7", 6); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "Speed8", 7); #RO - readingsEndUpdate($hash, 1); - - Log3 ($name, 4, "Vallox: Incoming Status-Info (FanSpeed-Relays): $datagram (Bits ".$hash->{"MR_".$Vallox_datatypes{$rawReadingType}}.")"); - - # MultiPurpose1 - } elsif ($rawReadingType eq "07") { - - $hash->{"MR_".$Vallox_datatypes{$rawReadingType}} = sprintf('%08b', hex("0x".$rawReadingValue)); - - $singlereading = 0; - readingsBeginUpdate($hash); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "PostHeating", 5); # RO - readingsEndUpdate($hash, 1); - - Log3 ($name, 4, "Vallox: Incoming Status-Info (MultiPurpose1): $datagram (Bits ".$hash->{"MR_".$Vallox_datatypes{$rawReadingType}}.")"); - - #MultiPurpose2 - } elsif ($rawReadingType eq "08") { - - $hash->{"MR_".$Vallox_datatypes{$rawReadingType}} = sprintf('%08b', hex("0x".$rawReadingValue)); - - $singlereading = 0; - readingsBeginUpdate($hash); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "DamperMotorPosition", 1); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "FaultSignalRelay", 2); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "SupplyFan", 3); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "PreHeating", 4); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "ExhaustFan", 5); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "FireplaceBooster", 6); #RO - readingsEndUpdate($hash, 1); - - Log3 ($name, 4, "Vallox: Incoming Status-Info (MultiPurpose2): $datagram (Bits ".$hash->{"MR_".$Vallox_datatypes{$rawReadingType}}.")"); - - #MachineInstalledCO2Sensor - } elsif ($rawReadingType eq "2D") { - - $hash->{"MR_".$Vallox_datatypes{$rawReadingType}} = sprintf('%08b', hex("0x".$rawReadingValue)); - - $singlereading = 0; - readingsBeginUpdate($hash); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "CO2Sensor1", 1); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "CO2Sensor2", 2); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "CO2Sensor3", 3); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "CO2Sensor4", 4); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "CO2Sensor5", 5); #RO - readingsEndUpdate($hash, 1); - - Log3 ($name, 4, "Vallox: Incoming Status-Info (MultiPurpose2): $datagram (Bits ".$hash->{"MR_".$Vallox_datatypes{$rawReadingType}}.")"); - - #Flags2 - } elsif ($rawReadingType eq "6D") { - - $hash->{"MR_".$Vallox_datatypes{$rawReadingType}} = sprintf('%08b', hex("0x".$rawReadingValue)); - - $singlereading = 0; - readingsBeginUpdate($hash); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "CO2HigherSpeedRequest", 0); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "CO2LowerRatePublicInvitation", 1); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "HumidityLowerRatePublicInvitation", 2); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "SwitchLowerSpeedRequest", 3); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "CO2Alarm", 6); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "FrostAlarmSensor", 7); - readingsEndUpdate($hash, 1); - - Log3 ($name, 4, "Vallox: Incoming Status-Info (Flags2): $datagram (Bits ".$hash->{"MR_".$Vallox_datatypes{$rawReadingType}}.")"); - - #Flags4 - } elsif ($rawReadingType eq "6F") { - - $hash->{"MR_".$Vallox_datatypes{$rawReadingType}} = sprintf('%08b', hex("0x".$rawReadingValue)); - - $singlereading = 0; - readingsBeginUpdate($hash); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "FrostAlarmWaterRadiator", 4); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "MasterSlaveSelection", 7); - readingsEndUpdate($hash, 1); - - Log3 ($name, 4, "Vallox: Incoming Status-Info (Flags4): $datagram (Bits ".$hash->{"MR_".$Vallox_datatypes{$rawReadingType}}.")"); - - #Flags5 - } elsif ($rawReadingType eq "70") { - - $hash->{"MR_".$Vallox_datatypes{$rawReadingType}} = sprintf('%08b', hex("0x".$rawReadingValue)); - - $singlereading = 0; - readingsBeginUpdate($hash); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "PreHeatingStatus", 7); - readingsEndUpdate($hash, 1); - - Log3 ($name, 4, "Vallox: Incoming Status-Info (Flags5): $datagram (Bits ".$hash->{"MR_".$Vallox_datatypes{$rawReadingType}}.")"); - - #Flags6 - } elsif ($rawReadingType eq "71") { - - $hash->{"MR_".$Vallox_datatypes{$rawReadingType}} = sprintf('%08b', hex("0x".$rawReadingValue)); - - $singlereading = 0; - readingsBeginUpdate($hash); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "RemoteMonitoringControl", 4); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "FireplaceSwitchActivation", 5); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "FireplaceBoosterStatus", 6); #RO - readingsEndUpdate($hash, 1); - - Log3 ($name, 4, "Vallox: Incoming Status-Info (Flags6): $datagram (Bits ".$hash->{"MR_".$Vallox_datatypes{$rawReadingType}}.")"); - - # Select - } elsif ($rawReadingType eq "A3") { - - $hash->{"MR_".$Vallox_datatypes{$rawReadingType}} = sprintf('%08b', hex("0x".$rawReadingValue)); - - $singlereading = 0; - readingsBeginUpdate($hash); - - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "PowerState", 0); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "CO2AdjustState", 1); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "RHAdjustState", 2); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "HeatingState", 3); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "FilterGuardIndicator", 4); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "HeatingIndicator", 5); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "FaultIndicator", 6); #RO - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "ServiceReminderIndicator", 7); - - readingsEndUpdate($hash, 1); - - Log3 ($name, 4, "Vallox: Incoming Status-Info (Select): $datagram (Bits ".$hash->{"MR_".$Vallox_datatypes{$rawReadingType}}.")"); - - # Program - } elsif ($rawReadingType eq "AA") { - - $hash->{"MR_".$Vallox_datatypes{$rawReadingType}} = sprintf('%08b', hex("0x".$rawReadingValue)); - - $singlereading = 0; - readingsBeginUpdate($hash); - # ----xxxx - Nibble is one value // # TODO: Adopt Function - readingsBulkUpdate($hash, "HumidityCO2AdjustmentInterval", oct("0b"."0000".substr($hash->{"MR_".$Vallox_datatypes{$rawReadingType}},4,4))) if (ReadingsVal($name,"HumidityCO2AdjustmentInterval","unknown") ne oct("0b"."0000".substr($hash->{"MR_".$Vallox_datatypes{$rawReadingType}},4,4))); + # get the type of the datagram + $rawReadingType = substr( $datagram, 6, 2 ); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "AutomaticHumidityBasicLevelSeekerState", 4); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "BoostSwitchMode", 5); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "RadiatorType", 6); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "CascadeAdjust", 7); - readingsEndUpdate($hash, 1); - - Log3 ($name, 4, "Vallox: Incoming Status-Info (Program): $datagram (Bits ".$hash->{"MR_".$Vallox_datatypes{$rawReadingType}}.")"); - - # Program2 - } elsif ($rawReadingType eq "B5") { - - $hash->{"MR_".$Vallox_datatypes{$rawReadingType}} = sprintf('%08b', hex("0x".$rawReadingValue)); - - $singlereading = 0; - readingsBeginUpdate($hash); - Vallox_ReadingsBulkUpdateMultiReading($hash, $rawReadingType, "MaxSpeedLimitFunction", 0); - readingsEndUpdate($hash, 1); - - Log3 ($name, 4, "Vallox: Incoming Status-Info (Program2): $datagram (Bits ".$hash->{"MR_".$Vallox_datatypes{$rawReadingType}}.")"); - - # Convert Unused Binarys to bits (Just not to have Hex Readings) - } elsif ($rawReadingType eq "6C" || $rawReadingType eq "6E") { - - $fineReadingValue = sprintf('%08b', hex("0x".$rawReadingValue)); - - Log3 ($name, 4, "Vallox: Incoming Status-Info (Unused Binary): $datagram (Bits $fineReadingValue)"); - - - # Everything else - # All Readings shall be handled before - } else { - $fineReadingValue = $rawReadingValue; - $singlereading = 1; - - Log3 ($name, 2, "Vallox: Incoming unhandled datagram: $datagram"); - } - - if($Vallox_datatypes{$rawReadingType}) { - if ($singlereading == 1) { - Log3 ($name, 5, "Vallox: Update Reading: $fineReadingValue"); - - readingsSingleUpdate($hash,$Vallox_datatypes{$rawReadingType}, $fineReadingValue, 1); - - # Efficiency Calculation - # Is this Reading a Temp? - if (substr($Vallox_datatypes{$rawReadingType},0,4) eq "Temp") { - - # If HRC is in Bypass - Efficiency is 0 - if (ReadingsVal($name,"DamperMotorPosition",1) == 1) { - readingsSingleUpdate($hash,"EfficiencyIn", 0, 1); - readingsSingleUpdate($hash,"EfficiencyOut", 0, 1); - readingsSingleUpdate($hash,"EfficiencyAverage", 0, 1); - Log3 ($name, 5, "Vallox: Efficiency Override: HRC Bypass"); - - } else { - - my ($EfficiencyIn,$EfficiencyOut,$TempIncoming,$TempOutside,$TempInside,$TempExhaust) = 0; - - # Efficiency on Keep Temp Inside - # Do we have all nessecary Readings? - if (ReadingsVal($name,"TempIncoming","unknown") ne "unknown" && - ReadingsVal($name,"TempOutside","unknown") ne "unknown" && - ReadingsVal($name,"TempInside","unknown") ne "unknown") { - - - $TempIncoming = ReadingsVal($name,"TempIncoming",-100); - $TempOutside = ReadingsVal($name,"TempOutside",-100); - $TempInside = ReadingsVal($name,"TempInside",-100); - - - # Prevent DIV/0 (if Inside=Outside the HRC does nothing = 100% Efficient) - if ($TempInside-$TempOutside != 0) { - $EfficiencyIn = ($TempIncoming-$TempOutside)/($TempInside-$TempOutside)*100; - - $EfficiencyIn = 100 if ($EfficiencyIn > 100); - - Log3 ($name, 5, "Vallox: Efficiency Inside: (".$TempIncoming."-".$TempIncoming.")/(".$TempInside."-".$TempOutside.")*100 = ".$EfficiencyIn); - readingsSingleUpdate($hash,"EfficiencyIn", $EfficiencyIn, 1); - } else { - Log3 ($name, 5, "Vallox: Efficiency Inside (DIV/0 Prevention): (".$TempIncoming."-".$TempIncoming.")/(".$TempInside."-".$TempOutside.")*100 = 100"); - readingsSingleUpdate($hash,"EfficiencyIn", 100, 1); - } - } - - # Efficiency on Keep Temp Outside - # Do we have all nessecary Readings? - if (ReadingsVal($name,"TempOutside","unknown") ne "unknown" && - ReadingsVal($name,"TempIncoming","unknown") ne "unknown" && - ReadingsVal($name,"TempExhaust","unknown") ne "unknown") { - - $TempOutside = ReadingsVal($name,"TempOutside",-100); - $TempIncoming = ReadingsVal($name,"TempIncoming",-100); - $TempExhaust = ReadingsVal($name,"TempExhaust",-100); - - # Prevent DIV/0 (if Inside=Outside the HRC does nothing = 100% Efficient) - if ($TempOutside-$TempIncoming != 0) { - $EfficiencyOut = ($TempExhaust-$TempIncoming)/($TempOutside-$TempIncoming)*100; - $EfficiencyOut = 100 if ($EfficiencyOut > 100); - Log3 ($name, 5, "Vallox: Efficiency Outside: (".$TempExhaust."-".$TempIncoming.")/(".$TempOutside."-".$TempIncoming.")*100 = ".$EfficiencyOut); - readingsSingleUpdate($hash,"EfficiencyOut", $EfficiencyOut, 1); - } else { - Log3 ($name, 5, "Vallox: Efficiency Outside (DIV/0 Protection): (".$TempExhaust."-".$TempIncoming.")/(".$TempOutside."-".$TempIncoming.")*100 = 100"); - readingsSingleUpdate($hash,"EfficiencyOut", 100, 1); - } - } - - # Average Efficiency - if (ReadingsVal($name,"EfficiencyIn","unknown") ne "unknown" && - ReadingsVal($name,"EfficiencyOut","unknown") ne "unknown") { - $EfficiencyIn = ReadingsVal($name,"EfficiencyIn",-100); - $EfficiencyOut = ReadingsVal($name,"EfficiencyOut",-100); - - my $EfficiencyAverage = ($EfficiencyIn+$EfficiencyOut) / 2; - Log3 ($name, 5, "Vallox: Efficiency Average: (".$EfficiencyIn."+".$EfficiencyOut.")/2 = ".$EfficiencyAverage); + # get the value of the datagram + $rawReadingValue = substr( $datagram, 8, 2 ); - readingsSingleUpdate($hash,"EfficiencyAverage", $EfficiencyAverage, 1); - } else { - Log3 ($name, 5, "Vallox: Efficiency Average unknown: (".ReadingsVal($name,"EfficiencyIn","unknown")."+".ReadingsVal($name,"EfficiencyOut","unknown").")/2"); - } - } - } - } - - } else { - Log3 ($name, 4, "Vallox: Datagram not in Datatypes-Table: ".$datagram); - } - } else { - Log3 ($name, 5, "Vallox: Incoming Status-Request: $datagram"); - } + # get the value of the datagram + $rawReadingChecksum = substr( $datagram, 10, 2 ); + + if ( $rawReadingType ne "00" ) { + + # Decoding for the final readings. + # - rawReading... is the original information from the datagram + # - fineReading... is the human readable information + + # Starting with the "One information in one datagram"-Section + + # Convert FanSpeeds by the Vallox_levelTable + if ( $rawReadingType eq "29" + || $rawReadingType eq "A5" + || $rawReadingType eq "A9" ) + { + $fineReadingValue = $Vallox_levelTable{$rawReadingValue}; + Log3( $name, 4, +"Vallox: Incoming Status-Info (FanSpeed): $datagram (Level $fineReadingValue)" + ); + + # Convert Temperatures by the Vallox_temperatureTable + } + elsif ($rawReadingType eq "32" + || $rawReadingType eq "33" + || $rawReadingType eq "34" + || $rawReadingType eq "35" + || $rawReadingType eq "A4" + || $rawReadingType eq "A7" + || $rawReadingType eq "A8" + || $rawReadingType eq "AF" ) + { + + if ( $rawReadingType eq "A4" && $hash->{BusVersion} eq "1" ) { + $fineReadingValue = $Vallox_levelTable{$rawReadingValue}; + + Log3( $name, 4, +"Vallox: Incoming Status-Info (HeatingSetPoint): $datagram (Level $fineReadingValue)" + ); + return; + } + else { + $fineReadingValue = $Vallox_temperatureTable{$rawReadingValue}; + } + + if ( + ( + $rawReadingType eq "32" + || $rawReadingType eq "33" + || $rawReadingType eq "34" + || $rawReadingType eq "35" + ) + && $fineReadingValue < -40 + ) + { + Log3( $name, 4, +"Vallox: Incoming Status-Info (Temperature) invalid: $datagram ($fineReadingValue deg.)" + ); + return; + } + Log3( $name, 4, +"Vallox: Incoming Status-Info (Temperature): $datagram ($fineReadingValue deg.)" + ); + + # Convert Percentages by the Vallox_percentageTable + } + elsif ( $rawReadingType eq "AE" ) { + $fineReadingValue = $Vallox_percentageTable{$rawReadingValue}; + Log3( $name, 4, +"Vallox: Incoming Status-Info (Percentage): $datagram ($fineReadingValue pct.)" + ); + + # Convert Faults by the Vallox_faultTable + } + elsif ( $rawReadingType eq "36" ) { + $fineReadingValue = $Vallox_faultTable{$rawReadingValue}; + Log3( $name, 4, +"Vallox: Incoming Status-Info (Fault): $datagram ($fineReadingValue)" + ); + + # Convert Decimal Values + } + elsif ($rawReadingType eq "2B" + || $rawReadingType eq "2C" + || $rawReadingType eq "2E" + || $rawReadingType eq "57" + || $rawReadingType eq "A6" + || $rawReadingType eq "79" + || $rawReadingType eq "8F" + || $rawReadingType eq "91" + || $rawReadingType eq "AB" + || $rawReadingType eq "B0" + || $rawReadingType eq "B1" + || $rawReadingType eq "B3" + || $rawReadingType eq "B4" ) + { + $fineReadingValue = sprintf( "%d", hex "0x" . $rawReadingValue ); + Log3( $name, 4, +"Vallox: Incoming Status-Info (Decimal): $datagram ($fineReadingValue)" + ); + + # Convert PostHeating Time Values + } + elsif ( $rawReadingType eq "55" || $rawReadingType eq "56" ) { + $fineReadingValue = + sprintf( "%d", hex "0x" . $rawReadingValue ) / 2.5; + Log3( $name, 4, +"Vallox: Incoming Status-Info (PostHeatingCounter): $datagram ($fineReadingValue)" + ); + + # Convert CellDefrostingSetpointTemperature Values + } + elsif ( $rawReadingType eq "B2" ) { + $fineReadingValue = + sprintf( "%d", hex "0x" . $rawReadingValue ) / 3; + Log3( $name, 4, +"Vallox: Incoming Status-Info (CellDefrostingSetpointTemperature): $datagram ($fineReadingValue)" + ); + +# Convert measured humidity by formula (if it is negative then you don't have a humidity sensor) + } + elsif ($rawReadingType eq "2A" + || $rawReadingType eq "2F" + || $rawReadingType eq "30" ) + { + $fineReadingValue = + ( sprintf( "%d", hex "0x" . $rawReadingValue ) - 51 ) / 2.04; + + # Negative Humidity impossible: No Sensor attatched + if ( $fineReadingValue < 0 ) { + Log3( $name, 4, +"Vallox: Incoming Status-Info (Humidity) invalid: $datagram ($fineReadingValue Perc. rH)" + ); + return; + } + + Log3( $name, 4, +"Vallox: Incoming Status-Info (Humidity): $datagram ($fineReadingValue pct. rH)" + ); + + # Starting with the "Up to eight informations in one datagram"-Section + # Disabled lines are unused. + + # FanSpeed-Relays + } + elsif ( $rawReadingType eq "06" ) { + + $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } = + sprintf( '%08b', hex( "0x" . $rawReadingValue ) ); + + $singlereading = 0; + readingsBeginUpdate($hash); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "Speed1", 0 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "Speed2", 1 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "Speed3", 2 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "Speed4", 3 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "Speed5", 4 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "Speed6", 5 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "Speed7", 6 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "Speed8", 7 ); #RO + readingsEndUpdate( $hash, 1 ); + + Log3( $name, 4, +"Vallox: Incoming Status-Info (FanSpeed-Relays): $datagram (Bits " + . $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } + . ")" ); + + # MultiPurpose1 + } + elsif ( $rawReadingType eq "07" ) { + + $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } = + sprintf( '%08b', hex( "0x" . $rawReadingValue ) ); + + $singlereading = 0; + readingsBeginUpdate($hash); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "PostHeating", 5 ); # RO + readingsEndUpdate( $hash, 1 ); + + Log3( $name, 4, + "Vallox: Incoming Status-Info (MultiPurpose1): $datagram (Bits " + . $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } + . ")" ); + + #MultiPurpose2 + } + elsif ( $rawReadingType eq "08" ) { + + $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } = + sprintf( '%08b', hex( "0x" . $rawReadingValue ) ); + + $singlereading = 0; + readingsBeginUpdate($hash); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "DamperMotorPosition", 1 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "FaultSignalRelay", 2 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "SupplyFan", 3 ); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "PreHeating", 4 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "ExhaustFan", 5 ); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "FireplaceBooster", 6 ); #RO + readingsEndUpdate( $hash, 1 ); + + Log3( $name, 4, + "Vallox: Incoming Status-Info (MultiPurpose2): $datagram (Bits " + . $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } + . ")" ); + + #MachineInstalledCO2Sensor + } + elsif ( $rawReadingType eq "2D" ) { + + $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } = + sprintf( '%08b', hex( "0x" . $rawReadingValue ) ); + + $singlereading = 0; + readingsBeginUpdate($hash); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "CO2Sensor1", 1 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "CO2Sensor2", 2 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "CO2Sensor3", 3 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "CO2Sensor4", 4 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "CO2Sensor5", 5 ); #RO + readingsEndUpdate( $hash, 1 ); + + Log3( $name, 4, + "Vallox: Incoming Status-Info (MultiPurpose2): $datagram (Bits " + . $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } + . ")" ); + + #Flags2 + } + elsif ( $rawReadingType eq "6D" ) { + + $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } = + sprintf( '%08b', hex( "0x" . $rawReadingValue ) ); + + $singlereading = 0; + readingsBeginUpdate($hash); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "CO2HigherSpeedRequest", 0 ); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "CO2LowerRatePublicInvitation", 1 ); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "HumidityLowerRatePublicInvitation", 2 ); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "SwitchLowerSpeedRequest", 3 ); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "CO2Alarm", 6 ); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "FrostAlarmSensor", 7 ); + readingsEndUpdate( $hash, 1 ); + + Log3( $name, 4, + "Vallox: Incoming Status-Info (Flags2): $datagram (Bits " + . $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } + . ")" ); + + #Flags4 + } + elsif ( $rawReadingType eq "6F" ) { + + $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } = + sprintf( '%08b', hex( "0x" . $rawReadingValue ) ); + + $singlereading = 0; + readingsBeginUpdate($hash); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "FrostAlarmWaterRadiator", 4 ); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "MasterSlaveSelection", 7 ); + readingsEndUpdate( $hash, 1 ); + + Log3( $name, 4, + "Vallox: Incoming Status-Info (Flags4): $datagram (Bits " + . $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } + . ")" ); + + #Flags5 + } + elsif ( $rawReadingType eq "70" ) { + + $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } = + sprintf( '%08b', hex( "0x" . $rawReadingValue ) ); + + $singlereading = 0; + readingsBeginUpdate($hash); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "PreHeatingStatus", 7 ); + readingsEndUpdate( $hash, 1 ); + + Log3( $name, 4, + "Vallox: Incoming Status-Info (Flags5): $datagram (Bits " + . $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } + . ")" ); + + #Flags6 + } + elsif ( $rawReadingType eq "71" ) { + + $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } = + sprintf( '%08b', hex( "0x" . $rawReadingValue ) ); + + $singlereading = 0; + readingsBeginUpdate($hash); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "RemoteMonitoringControl", 4 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "FireplaceSwitchActivation", 5 ); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "FireplaceBoosterStatus", 6 ); #RO + readingsEndUpdate( $hash, 1 ); + + Log3( $name, 4, + "Vallox: Incoming Status-Info (Flags6): $datagram (Bits " + . $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } + . ")" ); + + # Select + } + elsif ( $rawReadingType eq "A3" ) { + + $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } = + sprintf( '%08b', hex( "0x" . $rawReadingValue ) ); + + $singlereading = 0; + readingsBeginUpdate($hash); + + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "PowerState", 0 ); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "CO2AdjustState", 1 ); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "RHAdjustState", 2 ); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "HeatingState", 3 ); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "FilterGuardIndicator", 4 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "HeatingIndicator", 5 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "FaultIndicator", 6 ); #RO + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "ServiceReminderIndicator", 7 ); + + readingsEndUpdate( $hash, 1 ); + + Log3( $name, 4, + "Vallox: Incoming Status-Info (Select): $datagram (Bits " + . $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } + . ")" ); + + # Program + } + elsif ( $rawReadingType eq "AA" ) { + + $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } = + sprintf( '%08b', hex( "0x" . $rawReadingValue ) ); + + $singlereading = 0; + readingsBeginUpdate($hash); + + # ----xxxx - Nibble is one value // # TODO: Adopt Function + readingsBulkUpdate( + $hash, + "HumidityCO2AdjustmentInterval", + oct( + "0b" . "0000" + . substr( + $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} }, + 4, 4 + ) + ) + ) + if ( + ReadingsVal( + $name, "HumidityCO2AdjustmentInterval", "unknown" + ) ne oct( + "0b" . "0000" + . substr( + $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} }, + 4, 4 + ) + ) + ); + + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "AutomaticHumidityBasicLevelSeekerState", 4 ); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "BoostSwitchMode", 5 ); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "RadiatorType", 6 ); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "CascadeAdjust", 7 ); + readingsEndUpdate( $hash, 1 ); + + Log3( $name, 4, + "Vallox: Incoming Status-Info (Program): $datagram (Bits " + . $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } + . ")" ); + + # Program2 + } + elsif ( $rawReadingType eq "B5" ) { + + $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } = + sprintf( '%08b', hex( "0x" . $rawReadingValue ) ); + + $singlereading = 0; + readingsBeginUpdate($hash); + Vallox_ReadingsBulkUpdateMultiReading( $hash, $rawReadingType, + "MaxSpeedLimitFunction", 0 ); + readingsEndUpdate( $hash, 1 ); + + Log3( $name, 4, + "Vallox: Incoming Status-Info (Program2): $datagram (Bits " + . $hash->{ "MR_" . $Vallox_datatypes{$rawReadingType} } + . ")" ); + + # Convert Unused Binarys to bits (Just not to have Hex Readings) + } + elsif ( $rawReadingType eq "6C" || $rawReadingType eq "6E" ) { + + $fineReadingValue = + sprintf( '%08b', hex( "0x" . $rawReadingValue ) ); + + Log3( $name, 4, +"Vallox: Incoming Status-Info (Unused Binary): $datagram (Bits $fineReadingValue)" + ); + + # Everything else + # All Readings shall be handled before + } + else { + $fineReadingValue = $rawReadingValue; + $singlereading = 1; + + Log3( $name, 2, "Vallox: Incoming unhandled datagram: $datagram" ); + } + + if ( $Vallox_datatypes{$rawReadingType} ) { + if ( $singlereading == 1 ) { + Log3( $name, 5, "Vallox: Update Reading: $fineReadingValue" ); + + readingsSingleUpdate( $hash, $Vallox_datatypes{$rawReadingType}, + $fineReadingValue, 1 ); + + # Efficiency Calculation + # Is this Reading a Temp? + if ( + substr( $Vallox_datatypes{$rawReadingType}, 0, 4 ) eq + "Temp" ) + { + + # If HRC is in Bypass - Efficiency is 0 + if ( ReadingsVal( $name, "DamperMotorPosition", 1 ) == 1 ) { + readingsSingleUpdate( $hash, "EfficiencyIn", 0, 1 ); + readingsSingleUpdate( $hash, "EfficiencyOut", 0, 1 ); + readingsSingleUpdate( $hash, "EfficiencyAverage", 0, + 1 ); + Log3( $name, 5, + "Vallox: Efficiency Override: HRC Bypass" ); + + } + else { + + my ( + $EfficiencyIn, $EfficiencyOut, $TempIncoming, + $TempOutside, $TempInside, $TempExhaust + ) = 0; + + # Efficiency on Keep Temp Inside + # Do we have all nessecary Readings? + if ( ReadingsVal( $name, "TempIncoming", "unknown" ) ne + "unknown" + && ReadingsVal( $name, "TempOutside", "unknown" ) ne + "unknown" + && ReadingsVal( $name, "TempInside", "unknown" ) ne + "unknown" ) + { + + $TempIncoming = + ReadingsVal( $name, "TempIncoming", -100 ); + $TempOutside = + ReadingsVal( $name, "TempOutside", -100 ); + $TempInside = + ReadingsVal( $name, "TempInside", -100 ); + + # Prevent DIV/0 (if Inside=Outside the HRC does nothing = 100% Efficient) + if ( $TempInside - $TempOutside != 0 ) { + $EfficiencyIn = + ( $TempIncoming - $TempOutside ) / + ( $TempInside - $TempOutside ) * 100; + + $EfficiencyIn = 100 if ( $EfficiencyIn > 100 ); + + Log3( $name, 5, + "Vallox: Efficiency Inside: (" + . $TempIncoming . "-" + . $TempIncoming . ")/(" + . $TempInside . "-" + . $TempOutside + . ")*100 = " + . $EfficiencyIn ); + readingsSingleUpdate( $hash, "EfficiencyIn", + $EfficiencyIn, 1 ); + } + else { + Log3( $name, 5, +"Vallox: Efficiency Inside (DIV/0 Prevention): (" + . $TempIncoming . "-" + . $TempIncoming . ")/(" + . $TempInside . "-" + . $TempOutside + . ")*100 = 100" ); + readingsSingleUpdate( $hash, "EfficiencyIn", + 100, 1 ); + } + } + + # Efficiency on Keep Temp Outside + # Do we have all nessecary Readings? + if ( ReadingsVal( $name, "TempOutside", "unknown" ) ne + "unknown" + && ReadingsVal( $name, "TempIncoming", "unknown" ) + ne "unknown" + && ReadingsVal( $name, "TempExhaust", "unknown" ) ne + "unknown" ) + { + + $TempOutside = + ReadingsVal( $name, "TempOutside", -100 ); + $TempIncoming = + ReadingsVal( $name, "TempIncoming", -100 ); + $TempExhaust = + ReadingsVal( $name, "TempExhaust", -100 ); + + # Prevent DIV/0 (if Inside=Outside the HRC does nothing = 100% Efficient) + if ( $TempOutside - $TempIncoming != 0 ) { + $EfficiencyOut = + ( $TempExhaust - $TempIncoming ) / + ( $TempOutside - $TempIncoming ) * 100; + $EfficiencyOut = 100 + if ( $EfficiencyOut > 100 ); + Log3( $name, 5, + "Vallox: Efficiency Outside: (" + . $TempExhaust . "-" + . $TempIncoming . ")/(" + . $TempOutside . "-" + . $TempIncoming + . ")*100 = " + . $EfficiencyOut ); + readingsSingleUpdate( $hash, "EfficiencyOut", + $EfficiencyOut, 1 ); + } + else { + Log3( $name, 5, +"Vallox: Efficiency Outside (DIV/0 Protection): (" + . $TempExhaust . "-" + . $TempIncoming . ")/(" + . $TempOutside . "-" + . $TempIncoming + . ")*100 = 100" ); + readingsSingleUpdate( $hash, "EfficiencyOut", + 100, 1 ); + } + } + + # Average Efficiency + if ( ReadingsVal( $name, "EfficiencyIn", "unknown" ) ne + "unknown" + && ReadingsVal( $name, "EfficiencyOut", "unknown" ) + ne "unknown" ) + { + $EfficiencyIn = + ReadingsVal( $name, "EfficiencyIn", -100 ); + $EfficiencyOut = + ReadingsVal( $name, "EfficiencyOut", -100 ); + + my $EfficiencyAverage = + ( $EfficiencyIn + $EfficiencyOut ) / 2; + Log3( $name, 5, + "Vallox: Efficiency Average: (" + . $EfficiencyIn . "+" + . $EfficiencyOut + . ")/2 = " + . $EfficiencyAverage ); + + readingsSingleUpdate( $hash, "EfficiencyAverage", + $EfficiencyAverage, 1 ); + } + else { + Log3( + $name, 5, + "Vallox: Efficiency Average unknown: (" + . ReadingsVal( $name, "EfficiencyIn", + "unknown" ) + . "+" + . ReadingsVal( $name, "EfficiencyOut", + "unknown" ) + . ")/2" + ); + } + } + } + } + + } + else { + Log3( $name, 4, + "Vallox: Datagram not in Datatypes-Table: " . $datagram ); + } + } + else { + Log3( $name, 5, "Vallox: Incoming Status-Request: $datagram" ); + } } @@ -775,263 +1400,325 @@ sub Vallox_InterpretAndUpdate(@) { # Default Functions ############################################## ################################## -sub -Vallox_Initialize($) -{ +sub Vallox_Initialize($) { my ($hash) = @_; require "$attr{global}{modpath}/FHEM/DevIo.pm"; - - $hash->{DefFn} = "Vallox_Define"; - $hash->{UndefFn} = "Vallox_Undef"; - $hash->{DeleteFn} = "Vallox_Delete"; - $hash->{SetFn} = "Vallox_Set"; - $hash->{GetFn} = "Vallox_Get"; - $hash->{AttrFn} = "Vallox_Attr"; -# $hash->{NotifyFn} = "Vallox_Notify"; - $hash->{ReadFn} = "Vallox_Read"; -# $hash->{ReadyFn} = "Vallox_Ready"; + $hash->{DefFn} = "Vallox_Define"; + $hash->{UndefFn} = "Vallox_Undef"; + $hash->{DeleteFn} = "Vallox_Delete"; + $hash->{SetFn} = "Vallox_Set"; + $hash->{GetFn} = "Vallox_Get"; + $hash->{AttrFn} = "Vallox_Attr"; + + # $hash->{NotifyFn} = "Vallox_Notify"; + $hash->{ReadFn} = "Vallox_Read"; + + # $hash->{ReadyFn} = "Vallox_Ready"; $hash->{ShutdownFn} = "Vallox_Shutdown"; - - $hash->{AttrList} = "ValloxBufferDebug:0,1 ValloxForceBroadcast:0,1 ValloxProcessOwnCommands:0,1 ValloxIDDomain ValloxIDFHEM ValloxIDCentral ".$readingFnAttributes; - + + $hash->{AttrList} = +"ValloxBufferDebug:0,1 ValloxForceBroadcast:0,1 ValloxProcessOwnCommands:0,1 ValloxIDDomain ValloxIDFHEM ValloxIDCentral " + . $readingFnAttributes; } ################################## sub Vallox_Define($) { - - my ($hash, $def) = @_; - my @a = split("[ \t][ \t]*", $def); - if(@a != 3 && @a != 4) { - my $msg = "wrong syntax: define Vallox devicename[\@baudrate] [busversion]"; - Log3 undef, 2, "Vallox: ".$msg; + + my ( $hash, $def ) = @_; + my @a = split( "[ \t][ \t]*", $def ); + if ( @a != 3 && @a != 4 ) { + my $msg = +"wrong syntax: define Vallox devicename[\@baudrate] [busversion]"; + Log3 undef, 2, "Vallox: " . $msg; return $msg; } DevIo_CloseDev($hash); my $name = $a[0]; - my $dev = $a[2]; - $hash-> {BusVersion} = "2"; - - - $dev .= "\@9600" if( $dev !~ m/\@/ && $def !~ m/:/ ); - $hash-> {DeviceName} = $dev; - - if(@a == 4) { - $hash-> {BusVersion} = $a[3]; + my $dev = $a[2]; + $hash->{BusVersion} = "2"; + + $dev .= "\@9600" if ( $dev !~ m/\@/ && $def !~ m/:/ ); + $hash->{DeviceName} = $dev; + + if ( @a == 4 ) { + $hash->{BusVersion} = $a[3]; } - - - if ($hash->{BusVersion} eq "1") { - %Vallox_datatypes = (%Vallox_datatypes_legacy1, %Vallox_datatypes_base); - %Vallox_datatypesReverse = (%Vallox_datatypesReverse_legacy1, %Vallox_datatypesReverse_base); - } else { + if ( $hash->{BusVersion} eq "1" ) { - %Vallox_datatypes = %Vallox_datatypes_base; - %Vallox_datatypesReverse = %Vallox_datatypesReverse_base; - } - - - my $ret = DevIo_OpenDev($hash, 0, undef); + %Vallox_datatypes = + ( %Vallox_datatypes_legacy1, %Vallox_datatypes_base ); + %Vallox_datatypesReverse = + ( %Vallox_datatypesReverse_legacy1, %Vallox_datatypesReverse_base ); + } + else { + + %Vallox_datatypes = %Vallox_datatypes_base; + %Vallox_datatypesReverse = %Vallox_datatypesReverse_base; + } + + my $ret = DevIo_OpenDev( $hash, 0, undef ); return $ret; } ################################## -sub Vallox_Undef($$) -{ - my ($hash, $name) = @_; - DevIo_CloseDev($hash); - RemoveInternalTimer($hash); - return undef; +sub Vallox_Undef($$) { + my ( $hash, $name ) = @_; + DevIo_CloseDev($hash); + RemoveInternalTimer($hash); + return undef; } ################################## -sub Vallox_Delete($$) -{ - my ( $hash, $name ) = @_; +sub Vallox_Delete($$) { + my ( $hash, $name ) = @_; - return undef; + return undef; } - ################################## -sub Vallox_Get($@) -{ +sub Vallox_Get($@) { my ( $hash, @a ) = @_; return "\"get Vallox\" needs at least one argument" if ( @a < 2 ); my $name = shift @a; - my $cmd = shift @a; - my $arg = shift @a; + my $cmd = shift @a; + my $arg = shift @a; - # "reading" is a predefined list of readings from the bus - if ($cmd eq "reading") { - - my $argKey = $Vallox_datatypesReverse{$arg}; - my $msg = Vallox_CreateMsg ($hash,$argKey); - - DevIo_SimpleWrite ($hash,$msg,1); - - Log3 ($name, 3, "Vallox: Request ".$msg." has been sent."); - return undef; - - # "update" shall be ask for all possible data. - # Not working at the moment. Need a new idea :( - } elsif ($cmd eq "update"){ - - while (my ($argKey, $argValue) = each %Vallox_datatypes) { - my $msg = Vallox_CreateMsg ($hash,$argKey); - DevIo_SimpleWrite ($hash,$msg,1); - } - return undef; - - # "raw is a custom Hex Code - } elsif ($cmd eq "raw"){ - return "Usage: get $name raw {HexValue}" if (!defined ($arg) || $arg =~ m/[^a-fA-F0-9]{2}/); - - my $msg = Vallox_CreateMsg ($hash,$arg); - - DevIo_SimpleWrite ($hash,$msg,1); - Log3 ($name, 3, "Vallox: Request ".$msg." has been sent."); - - return undef; - } else { - my $retmsg; - my @commandList = keys %Vallox_gets; - my $commandCount = keys %Vallox_gets; - - my @readingList = keys %Vallox_datatypesReverse; - my $readingCount = keys %Vallox_datatypesReverse; - - - $retmsg .= join(" ", @commandList) if ($commandCount > 0); - $retmsg .= " reading:".join(",", sort @readingList) if ($readingCount > 0); - - ## Ich kann nicht alle befehle bulken. ... :( - # $retmsg .= " update:noArg"; - - Log3 ($name, 2, "Vallox: Unknown argument $cmd.") if( $cmd ne '?' && $cmd ne ''); + # "reading" is a predefined list of readings from the bus + if ( $cmd eq "reading" ) { + + my $argKey = $Vallox_datatypesReverse{$arg}; + my $msg = Vallox_CreateMsg( $hash, $argKey ); + + DevIo_SimpleWrite( $hash, $msg, 1 ); + + Log3( $name, 3, "Vallox: Request " . $msg . " has been sent." ); + return undef; + + # "update" shall be ask for all possible data. + # Not working at the moment. Need a new idea :( + } + elsif ( $cmd eq "update" ) { + + while ( my ( $argKey, $argValue ) = each %Vallox_datatypes ) { + my $msg = Vallox_CreateMsg( $hash, $argKey ); + DevIo_SimpleWrite( $hash, $msg, 1 ); + } + return undef; + + # "raw is a custom Hex Code + } + elsif ( $cmd eq "raw" ) { + return "Usage: get $name raw {HexValue}" + if ( !defined($arg) || $arg =~ m/[^a-fA-F0-9]{2}/ ); + + my $msg = Vallox_CreateMsg( $hash, $arg ); + + DevIo_SimpleWrite( $hash, $msg, 1 ); + Log3( $name, 3, "Vallox: Request " . $msg . " has been sent." ); + + return undef; + } + else { + my $retmsg; + my @commandList = keys %Vallox_gets; + my $commandCount = keys %Vallox_gets; + + my @readingList = keys %Vallox_datatypesReverse; + my $readingCount = keys %Vallox_datatypesReverse; + + $retmsg .= join( " ", @commandList ) if ( $commandCount > 0 ); + $retmsg .= " reading:" . join( ",", sort @readingList ) + if ( $readingCount > 0 ); + + ## Ich kann nicht alle befehle bulken. ... :( + # $retmsg .= " update:noArg"; + + Log3( $name, 2, "Vallox: Unknown argument $cmd." ) + if ( $cmd ne '?' && $cmd ne '' ); return "Unknown argument $cmd, choose one of " . $retmsg; - } + } } ################################## -sub Vallox_Set($@) -{ +sub Vallox_Set($@) { my ( $hash, @a ) = @_; return "\"set Vallox\" needs at least an argument" if ( @a < 2 ); - my $domain = hex "0x".AttrVal($hash->{NAME}, "ValloxIDDomain", "01"); # Domain (1 by default) - my $sender = hex "0x".AttrVal($hash->{NAME}, "ValloxIDFHEM", "2F"); # ID of this FHEM - my $receiver = hex "0x".AttrVal($hash->{NAME}, "ValloxIDCentral", "11"); # ID of the central - + my $domain = hex "0x" + . AttrVal( $hash->{NAME}, "ValloxIDDomain", "01" ) + ; # Domain (1 by default) + my $sender = hex "0x" + . AttrVal( $hash->{NAME}, "ValloxIDFHEM", "2F" ); # ID of this FHEM + my $receiver = hex "0x" + . AttrVal( $hash->{NAME}, "ValloxIDCentral", "11" ); # ID of the central my $name = shift @a; - my $cmd = shift @a; - my $arg = shift @a; - + my $cmd = shift @a; + my $arg = shift @a; + my $datatype; my $datavalue; - - my $setCommands; - my @commandList = keys %Vallox_sets; - my $commandCount = keys %Vallox_sets; - - $setCommands .= join(" ", @commandList) if ($commandCount > 0); - $setCommands .= " FanSpeed:1,2,3,4,5,6,7,8"; - $setCommands .= " BasicHumidityLevel:slider,0,1,100"; - $setCommands .= " HeatRecoveryCellBypassSetpointTemperature:slider,0,1,20"; - - foreach my $MR_key (keys %Vallox_multiReadingTable_realcmd) { - $setCommands .= " ".$MR_key.":0,1"; - } - - # MR: Prepare Values and Command for datagram - if (exists($Vallox_multiReadingTable_realcmd{$cmd}) && exists($hash->{"MR_".$cmd})) { - # TODO: Integrate get before set; - return "Vallox: Internal ".$Vallox_multiReadingTable_realcmd{$cmd}." empty (".$hash->{"MR_".$cmd}."). Read ".$Vallox_multiReadingTable_realcmd{$cmd}." first!" if ($hash->{"MR_".$Vallox_multiReadingTable_realcmd{$cmd}} eq ""); - - $arg = Vallox_ReplaceBit($hash, $hash->{"MR_".$cmd}, $Vallox_multiReadingTable_digit{$cmd}, $arg); - $cmd = $Vallox_multiReadingTable_realcmd{$cmd} - } - - ## TODO - if (exists $Vallox_datatypesReverse{$cmd}) { - - $datatype = hex "0x".$Vallox_datatypesReverse{$cmd}; - - if ($datatype == 0x29) { - $datavalue = hex "0x".$Vallox_levelTableReverse{$arg}; - } elsif ($datatype == 0xae) { - $datavalue = hex "0x".$Vallox_percentageTableReverse{$arg}; - } elsif ($datatype == 0xaf) { - $datavalue = hex "0x".$Vallox_temperatureTableReverse{$arg}; - } else { - $datavalue = hex "0x".$arg; - } - - } elsif ($cmd eq "raw") { - $datatype = hex "0x".substr($arg,0,2); - $datavalue = hex "0x".substr($arg,2,2); + my $setCommands; + my @commandList = keys %Vallox_sets; + my $commandCount = keys %Vallox_sets; - } else { - Log3 ($name, 2, "Vallox: Unknown argument $cmd.") if( $cmd ne '?' && $cmd ne ''); + $setCommands .= join( " ", @commandList ) if ( $commandCount > 0 ); + $setCommands .= " FanSpeed:slider,1,1,8"; + $setCommands .= " FanSpeedMin:slider,1,1,8"; + $setCommands .= " FanSpeedMax:slider,1,1,8"; + $setCommands .= " BasicHumidityLevel:slider,0,1,100"; + $setCommands .= " HeatRecoveryCellBypassSetpointTemperature:slider,0,1,20"; + $setCommands .= " ServiceReminderMonths:slider,1,1,15"; + + foreach my $MR_key ( keys %Vallox_multiReadingTable_realcmd ) { + $setCommands .= " " . $MR_key . ":0,1"; + } + + # MR: Prepare Values and Command for datagram + if ( exists( $Vallox_multiReadingTable_realcmd{$cmd} ) + && exists( $hash->{ "MR_" . $Vallox_multiReadingTable_realcmd{$cmd} } ) + ) + { + + # TODO: Integrate get before set; + return + "Vallox: Internal " + . $Vallox_multiReadingTable_realcmd{$cmd} + . " empty (" + . $hash->{ "MR_" . $cmd } + . "). Read " + . $Vallox_multiReadingTable_realcmd{$cmd} + . " first!" + if ( + $hash->{ "MR_" . $Vallox_multiReadingTable_realcmd{$cmd} } eq "" ); + + $arg = Vallox_ReplaceBit( + $hash, + $hash->{ "MR_" . $Vallox_multiReadingTable_realcmd{$cmd} }, + $Vallox_multiReadingTable_digit{$cmd}, $arg + ); + $cmd = $Vallox_multiReadingTable_realcmd{$cmd}; + } + + ## TODO + if ( exists $Vallox_datatypesReverse{$cmd} ) { + + $datatype = hex "0x" . $Vallox_datatypesReverse{$cmd}; + + if ( $datatype == 0x29 || $datatype == 0xA5 || $datatype == 0xA9 ) { + $datavalue = hex "0x" . $Vallox_levelTableReverse{$arg}; + } + elsif ( $datatype == 0xae ) { + $datavalue = hex "0x" . $Vallox_percentageTableReverse{$arg}; + } + elsif ( $datatype == 0xaf ) { + $datavalue = hex "0x" . $Vallox_temperatureTableReverse{$arg}; + } + else { + $datavalue = hex "0x" . $arg; + } + + } + elsif ( $cmd eq "raw" ) { + + $datatype = hex "0x" . substr( $arg, 0, 2 ); + $datavalue = hex "0x" . substr( $arg, 2, 2 ); + + } + else { + Log3( $name, 2, "Vallox: Unknown argument $cmd." ) + if ( $cmd ne '?' && $cmd ne '' ); return "Unknown argument $cmd, choose one of " . $setCommands; - } - - my $checksum = ($domain + $sender + $receiver + $datatype + $datavalue) % 0x100; - my $msg = lc(sprintf("%02x", $domain).sprintf("%02x", $sender).sprintf("%02x", $receiver).sprintf("%02x", $datatype).sprintf("%02x", $datavalue).sprintf("%02x", $checksum)); + } - DevIo_SimpleWrite ($hash,$msg,1); - Log3 ($name, 3, "Vallox: Command ".$msg." has been sent."); - - if (AttrVal($hash->{NAME}, "ValloxProcessOwnCommands", "0") == 1 || $hash->{BusVersion} eq "1") { + my $checksum = + ( $domain + $sender + $receiver + $datatype + $datavalue ) % 0x100; + my $msg = + lc( + sprintf( "%02x", $domain ) + . sprintf( "%02x", $sender ) + . sprintf( "%02x", $receiver ) + . sprintf( "%02x", $datatype ) + . sprintf( "%02x", $datavalue ) + . sprintf( "%02x", $checksum ) ); - Vallox_InterpretAndUpdate($hash,$msg); - Log3 ($name, 3, "Vallox: Command ".$msg." has been internal processed."); - - } - if (AttrVal($hash->{NAME}, "ValloxForceBroadcast", "0") == 1 || $hash->{BusVersion} eq "1") { - $checksum = ($domain + $sender + 0x10 + $datatype + $datavalue) % 0x100; - $msg = lc(sprintf("%02x", $domain).sprintf("%02x", $sender). 10 .sprintf("%02x", $datatype).sprintf("%02x", $datavalue).sprintf("%02x", $checksum)); - DevIo_SimpleWrite ($hash,$msg,1); - Log3 ($name, 3, "Vallox: Broadcast-Command ".$msg." has been sent."); + DevIo_SimpleWrite( $hash, $msg, 1 ); + Log3( $name, 3, "Vallox: Command " . $msg . " has been sent." ); - $checksum = ($domain + $sender + 0x20 + $datatype + $datavalue) % 0x100; - $msg = lc(sprintf("%02x", $domain).sprintf("%02x", $sender). 20 .sprintf("%02x", $datatype).sprintf("%02x", $datavalue).sprintf("%02x", $checksum)); - DevIo_SimpleWrite ($hash,$msg,1); - Log3 ($name, 3, "Vallox: Broadcast-Command ".$msg." has been sent."); - } + if ( AttrVal( $hash->{NAME}, "ValloxProcessOwnCommands", "0" ) == 1 + || $hash->{BusVersion} eq "1" ) + { + + Vallox_InterpretAndUpdate( $hash, $msg ); + Log3( $name, 3, + "Vallox: Command " . $msg . " has been internal processed." ); + + } + if ( AttrVal( $hash->{NAME}, "ValloxForceBroadcast", "0" ) == 1 + || $hash->{BusVersion} eq "1" ) + { + $checksum = + ( $domain + $sender + 0x10 + $datatype + $datavalue ) % 0x100; + $msg = + lc( + sprintf( "%02x", $domain ) + . sprintf( "%02x", $sender ) + . 10 + . sprintf( "%02x", $datatype ) + . sprintf( "%02x", $datavalue ) + . sprintf( "%02x", $checksum ) ); + DevIo_SimpleWrite( $hash, $msg, 1 ); + Log3( $name, 3, + "Vallox: Broadcast-Command " . $msg . " has been sent." ); + + $checksum = + ( $domain + $sender + 0x20 + $datatype + $datavalue ) % 0x100; + $msg = + lc( + sprintf( "%02x", $domain ) + . sprintf( "%02x", $sender ) + . 20 + . sprintf( "%02x", $datatype ) + . sprintf( "%02x", $datavalue ) + . sprintf( "%02x", $checksum ) ); + DevIo_SimpleWrite( $hash, $msg, 1 ); + Log3( $name, 3, + "Vallox: Broadcast-Command " . $msg . " has been sent." ); + } - return undef; - + } -sub Vallox_Attr(@) -{ - my ($cmd,$name,$aName,$aVal) = @_; - # $cmd can be "del" || "set" - # $name is device name - # aName and aVal are Attribute name and value - if ($cmd eq "set") { - if ($aName eq "ValloxIDDomain" || $aName eq "ValloxIDFHEM" || $aName eq "ValloxIDCentral") { - - if ($aVal =~ m/[^a-fA-F0-9]/ || length($aVal) != 2) { - Log3 $name, 2, "Vallox: Invalid HexValue in attr $name $aName $aVal: $@"; - return "Invalid HexValue $aVal"; - } - } - } - return undef; +sub Vallox_Attr(@) { + my ( $cmd, $name, $aName, $aVal ) = @_; + + # $cmd can be "del" || "set" + # $name is device name + # aName and aVal are Attribute name and value + if ( $cmd eq "set" ) { + if ( $aName eq "ValloxIDDomain" + || $aName eq "ValloxIDFHEM" + || $aName eq "ValloxIDCentral" ) + { + + if ( $aVal =~ m/[^a-fA-F0-9]/ || length($aVal) != 2 ) { + Log3 $name, 2, + "Vallox: Invalid HexValue in attr $name $aName $aVal: $@"; + return "Invalid HexValue $aVal"; + } + } + } + return undef; } - -sub Vallox_Read($) -{ +sub Vallox_Read($) { my ($hash) = @_; my $name = $hash->{NAME}; my $datagram; @@ -1039,71 +1726,72 @@ sub Vallox_Read($) my $rawReadingValue; my $rawReadingChecksum; my $singlereading = 1; - + my $fineReadingValue = 1; - - my $bufferDebugName = AttrVal($hash->{NAME}, "ValloxBufferDebug", "0"); - + + my $bufferDebugName = AttrVal( $hash->{NAME}, "ValloxBufferDebug", "0" ); + # read from serial device - my $buf = DevIo_SimpleRead($hash); + my $buf = DevIo_SimpleRead($hash); return "" if ( !defined($buf) ); - - # Convert read data to hex and add to debug if nessecary - if ($bufferDebugName eq 1) { - $hash->{"BufferDebug"} .= unpack ('H*', $buf); - } - + + # Convert read data to hex and add to debug if nessecary + if ( $bufferDebugName eq 1 ) { + $hash->{"BufferDebug"} .= unpack( 'H*', $buf ); + } + # Convert read data to hex and fill DevIO-Buffer - $bufferDevIO .= unpack ('H*', $buf); - - # DO Run Validation until DevIO-Buffer is less than 2 chars long - do { - - # If DevIO-Buffer is filled add difference to 14 Chars to ReadBuffer and remove it from DevIO-Buffer - if (length($bufferDevIO) >= 2) { - - my $bufferReadSpace = 14 - length($bufferRead); - - $bufferRead .= substr($bufferDevIO,0,$bufferReadSpace); - - # If the bufferDevIO buffer is shorter than the filling, set it to empty to avoid error - if (length($bufferDevIO) >= $bufferReadSpace) { - $bufferDevIO = substr($bufferDevIO,$bufferReadSpace); - } else { - $bufferDevIO = ""; - } - } - - #$hash->{"BufferDevIOLength"} = length($bufferDevIO); - - # Once ReadBuffer filled up, remove first Byte - if (length($bufferRead) >= 14) { - $bufferRead = substr($bufferRead,2,12); - } - - # If ReadBuffer has valid length start validating content - if (length($bufferRead) == 12) { - if (Vallox_ValidateStream($hash) == 1) { - Log3 ($name, 5, "Vallox: Buffer: ".$bufferRead); - my $datagram = uc($bufferRead); - - Vallox_InterpretAndUpdate($hash,$datagram); - - } elsif (Vallox_ValidateStream($hash) == 2) { - Log3 ($name, 4, "Vallox: Invalid Status-Request: $bufferRead"); - } + $bufferDevIO .= unpack( 'H*', $buf ); - } - } while (length($bufferDevIO) >= 2); -} -sub Vallox_Shutdown($) -{ - my ($hash) = @_; + # DO Run Validation until DevIO-Buffer is less than 2 chars long + do { - DevIo_CloseDev($hash); - return undef; +# If DevIO-Buffer is filled add difference to 14 Chars to ReadBuffer and remove it from DevIO-Buffer + if ( length($bufferDevIO) >= 2 ) { + + my $bufferReadSpace = 14 - length($bufferRead); + + $bufferRead .= substr( $bufferDevIO, 0, $bufferReadSpace ); + +# If the bufferDevIO buffer is shorter than the filling, set it to empty to avoid error + if ( length($bufferDevIO) >= $bufferReadSpace ) { + $bufferDevIO = substr( $bufferDevIO, $bufferReadSpace ); + } + else { + $bufferDevIO = ""; + } + } + + #$hash->{"BufferDevIOLength"} = length($bufferDevIO); + + # Once ReadBuffer filled up, remove first Byte + if ( length($bufferRead) >= 14 ) { + $bufferRead = substr( $bufferRead, 2, 12 ); + } + + # If ReadBuffer has valid length start validating content + if ( length($bufferRead) == 12 ) { + if ( Vallox_ValidateStream($hash) == 1 ) { + Log3( $name, 5, "Vallox: Buffer: " . $bufferRead ); + my $datagram = uc($bufferRead); + + Vallox_InterpretAndUpdate( $hash, $datagram ); + + } + elsif ( Vallox_ValidateStream($hash) == 2 ) { + Log3( $name, 4, "Vallox: Invalid Status-Request: $bufferRead" ); + } + + } + } while ( length($bufferDevIO) >= 2 ); } +sub Vallox_Shutdown($) { + my ($hash) = @_; + + DevIo_CloseDev($hash); + return undef; +} 1; @@ -1318,4 +2006,3 @@ sub Vallox_Shutdown($) =end html_DE =cut -