Last active
January 15, 2019 04:33
-
-
Save maxlapshin/1c803f05dd90c2ae98655988208c990a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env escript | |
| %% | |
| %% | |
| -mode(compile). | |
| main([IP]) -> | |
| {ok, Socket} = gen_tcp:connect(IP, 1560, [binary, {active,false}]), | |
| loop(Socket); | |
| main([IP, "set_speed", Speed]) -> | |
| {ok, Socket} = gen_tcp:connect(IP, 1560, [binary, {active,false}]), | |
| call(Socket, set_speed, list_to_integer(Speed)), | |
| timer:sleep(2000), | |
| Stat = call(Socket, status), | |
| io:format("~s\n~160p\n", [maps:get(msg,Stat,""),Stat]), | |
| ok; | |
| main([IP, "set_zone_speed", Zone_, Speed_, Level_]) -> | |
| {ok, Socket} = gen_tcp:connect(IP, 1560, [binary, {active,false}]), | |
| Zone = list_to_integer(Zone_), | |
| Speed = case Speed_ of | |
| "-" -> undefined; | |
| _ -> list_to_integer(Speed_) | |
| end, | |
| Level = case Level_ of | |
| "-" -> undefined; | |
| _ -> list_to_integer(Level_) | |
| end, | |
| call(Socket, set_zone_speed, {Zone, Speed, Level}), | |
| timer:sleep(2000), | |
| io:format("Zone: ~160p\n", [call(Socket, zone_level, Zone)]), | |
| Stat = call(Socket, status), | |
| io:format("~s\n~160p\n", [maps:get(msg,Stat,""),Stat]), | |
| ok; | |
| main([IP, "set_power", Value]) -> | |
| {ok, Socket} = gen_tcp:connect(IP, 1560, [binary, {active,false}]), | |
| call(Socket, set_power, Value == "on"), | |
| timer:sleep(1000), | |
| Stat = call(Socket, status), | |
| io:format("~s\n~160p\n", [maps:get(msg,Stat,""),Stat]), | |
| ok; | |
| main([IP, "set_options", Key, Value_]) when Key == "mode"; Key == "humidifier"; Key == "comfort"; Key == "restart" -> | |
| {ok, Socket} = gen_tcp:connect(IP, 1560, [binary, {active,false}]), | |
| Value = case Value_ of | |
| "on" -> true; | |
| "off" -> false; | |
| "warm" -> warm; | |
| "cool" -> cool; | |
| "auto" -> auto; | |
| "disabled" -> disabled | |
| end, | |
| Arg = #{list_to_atom(Key) => Value}, | |
| call(Socket, set_options, Arg), | |
| timer:sleep(1000), | |
| Stat = call(Socket, status), | |
| io:format("~s\n~160p\n", [maps:get(msg,Stat,""),Stat]), | |
| ok. | |
| loop(Socket) -> | |
| HS = call(Socket, handshake), | |
| io:format("~160p\n", [HS]), | |
| Stat = call(Socket, status), | |
| io:format("~s\n~160p\n", [maps:get(msg,Stat,""),Stat]), | |
| io:format("Zone1: ~160p\n", [call(Socket, zone_level, 1)]), | |
| io:format("Zone2: ~160p\n", [call(Socket, zone_level, 2)]), | |
| io:format("Zone3: ~160p\n", [call(Socket, zone_level, 3)]), | |
| io:format("Zone4: ~160p\n", [call(Socket, zone_level, 4)]), | |
| io:format("Sensors: ~160p\n", [call(Socket, sensors)]), | |
| ok. | |
| call(Socket, Command) -> | |
| call(Socket, Command, undefined). | |
| call(Socket, Command, Argument) -> | |
| Code = case Command of | |
| handshake -> "VPr07"; | |
| status -> "VSt07"; | |
| zone_level -> "VZL0"++integer_to_list(Argument); | |
| sensors -> "VSens"; | |
| set_temperature -> "VWTmp"; | |
| set_power -> "VWPwr"; | |
| set_humidity -> "VWHum"; | |
| set_speed -> "VWSpd"; | |
| set_zone_speed -> "VWZon"; | |
| set_options -> "VWFtr" | |
| end, | |
| Postfix = case Command of | |
| set_power -> "_" ++ integer_to_list(case Argument of true -> 11; false -> 10 end, 16); | |
| set_temperature -> "_"++integer_to_list(Argument,16); | |
| set_humidity -> "_" ++ integer_to_list(Argument,16); | |
| set_speed -> "_"++ integer_to_list(Argument,16); | |
| set_zone_speed -> | |
| {ZoneNumber,TargetSpeedV,ZoneLevelV} = Argument, | |
| ZoneLevel = case ZoneLevelV of | |
| undefined -> 255; | |
| _ -> ZoneLevelV | |
| end, | |
| TargetSpeed = case TargetSpeedV of | |
| undefined -> 15; | |
| _ -> TargetSpeedV | |
| end, | |
| "_" ++ integer_to_list(TargetSpeed,16)++"_"++integer_to_list(ZoneNumber,16)++"_"++integer_to_list(ZoneLevel,16); | |
| set_options -> | |
| ModeSet = case maps:get(mode,Argument,undefined) of | |
| undefined -> 0; | |
| warm -> 1; | |
| cool -> 2; | |
| auto -> 3; | |
| disabled -> 4 | |
| end, | |
| HumidSet = case maps:get(humidifier,Argument,undefined) of | |
| undefined -> 0; | |
| true -> 1; | |
| false -> 2 | |
| end, | |
| Comfort = case maps:get(comfort,Argument,undefined) of | |
| undefined -> 0; | |
| true -> 1; | |
| false -> 2 | |
| end, | |
| Restart = case maps:get(restart,Argument,undefined) of | |
| undefined -> 0; | |
| true -> 1; | |
| false -> 2 | |
| end, | |
| <<B1:8,B2:8>> = <<0:7, Restart:2, Comfort:2, HumidSet:2, ModeSet:3>>, | |
| <<B:16>> = <<B1:8,B2:8>>, | |
| "_"++integer_to_list(B,16); | |
| _ -> | |
| "" | |
| end, | |
| ok = gen_tcp:send(Socket, [Code,"_70B6",Postfix]), | |
| {ok, Bin1} = gen_tcp:recv(Socket, 0), | |
| Reply = parse(Bin1), | |
| Reply. | |
| parse(<<"OK_",Command/binary>>) -> | |
| Parts = binary:split(Command, <<"_">>, [global]), | |
| {ok, Parts}; | |
| parse(<<Code:5/binary, "_", Command/binary>>) -> | |
| Parts = [if | |
| size(Part) == 3 orelse size(Part) == 4 -> <<(binary_to_integer(Part,16)):16/little>>; | |
| true -> Part | |
| end || Part <- binary:split(Command, <<"_">>, [global])], | |
| parse2(Code, Parts). | |
| parse2(<<"VSens">>, [<<>>, TInf, HInf, TRoom, HRoom, TOut, HOut, THF, <<Pwr1,Pwr2>>]) -> | |
| % D = fun(<<7,16#FB>>) -> undefined; | |
| % () | |
| #{ | |
| temp_vent => TInf, | |
| humidity_vent => HInf, | |
| temp_room => TRoom, | |
| humidity_room => HRoom, | |
| temp_out => TOut, | |
| humidity_out => HOut, | |
| temp_water => THF, | |
| power => binary:decode_unsigned(<<Pwr2,Pwr1>>) | |
| }; | |
| parse2(<<"VPr07">>, [<<TempMin, TempMax>>, <<SpeedMin, SpeedMax>>, <<HumidMin,HumidMax>>, | |
| Misc, Protocol, <<TPD1,TPD2>>, Controller| _Parts]) -> | |
| <<_:3, VavZones:5, IsAuto:1, HasCooler:1, HasHumid:1, HasCascH:1, HasCascT:1, ShowHumid:1, | |
| EnabledVavReg:1, EnabledVav:1>> = Misc, | |
| #{temp => [TempMin, TempMax], | |
| speed => [SpeedMin, SpeedMax], | |
| humidity => [HumidMin,HumidMax], | |
| vav_zone_count => VavZones, | |
| vav_enabled => EnabledVav == 1, | |
| vav_pressure_enabled => EnabledVavReg == 1, | |
| show_humidity => ShowHumid == 1, | |
| has_cascade_t => HasCascT == 1, | |
| has_cascade_h => HasCascH == 1, | |
| has_humidifier => HasHumid == 1, | |
| has_cooler => HasCooler == 1, | |
| has_auto_cooling => IsAuto == 1, | |
| protocol => Protocol, | |
| tpd => {TPD2,TPD1}, controller => binary:decode_unsigned(Controller)}; | |
| parse2(<<"VSt07">>, [<<S0,S1>>, <<M0,M1>>, <<TempCurrent,TempTarget>>, | |
| <<Humidity, HumidityTarget>>, <<SpeedTarget:4, Speed:4, SpeedFact:8>>, <<MS0,MS1>>, | |
| <<Min,Hour>>, <<Day,Month>>, <<Dow, Year>>, Msg|_]) -> | |
| <<PowerBlocked:1, ScenarioBlocked:1, HumidAuto:1, ComfortOn:1, RestartOn:1, | |
| SpeedIsDown:1, HumidOn:1, ModeSet:3, ChangeFilter:1, AutoOff:1, Overheat:1, | |
| HasError:1, HasWarning:1, PowerOn:1>> = <<S1,S0>>, | |
| State = #{ | |
| on => PowerOn == 1, | |
| has_warning => HasWarning == 1, | |
| has_error => HasError == 1, | |
| overheat => Overheat == 1, | |
| auto_off => AutoOff == 1, | |
| change_filter => ChangeFilter == 1, | |
| mode_set => case ModeSet of | |
| 1 -> warm; | |
| 2 -> cool; | |
| 3 -> auto; | |
| 4 -> disabled | |
| end, | |
| humidifier_enabled => HumidOn == 1, | |
| speed_is_down => SpeedIsDown == 1, | |
| restart_on => RestartOn == 1, | |
| comfort_on => ComfortOn == 1, | |
| auto_humidifier => HumidAuto == 1, | |
| scenario_blocked => ScenarioBlocked == 1, | |
| power_blocked => PowerBlocked == 1 | |
| }, | |
| <<NumIcoHF:3, WhoActivateScen:3, | |
| NumActiveScen:4, WorkModeCode:3, ScenAllow:1, UnitStateCode:2>> = <<M1,M0>>, | |
| Mode = #{ | |
| unit_state => case UnitStateCode of | |
| 0 -> off; | |
| 1 -> on; | |
| 2 -> turning_on; | |
| 3 -> turning_off | |
| end, | |
| scenario_allowed => ScenAllow == 1, | |
| current_mode => case WorkModeCode of | |
| 0 -> heating; | |
| 1 -> cooling; | |
| 2 -> auto_heating; | |
| 3 -> auto_cooling; | |
| 4 -> passthrough; | |
| 5 -> off | |
| end, | |
| active_scenario => NumActiveScen, | |
| scenario_activator => case WhoActivateScen of | |
| 0 -> disabled; | |
| 1 -> timer1; | |
| 2 -> timer2; | |
| 3 -> manual; | |
| 4 -> later | |
| end, | |
| current_icon => NumIcoHF | |
| }, | |
| <<FilterDust:8, ColorInd:2, ColorMsg:2, TempMin:4>> = <<MS1,MS0>>, | |
| Misc = #{ | |
| minimal_temp => TempMin, | |
| message_color => case ColorMsg of | |
| 0 -> normal; | |
| 1 -> warning; | |
| 2 -> error; | |
| 3 -> unknown | |
| end, | |
| indicator_color => case ColorInd of | |
| 0 -> off; | |
| 1 -> changing; | |
| 2 -> on | |
| end, | |
| filter => FilterDust | |
| }, | |
| #{state => State, mode => Mode, temperature => TempCurrent, temp_target => TempTarget, | |
| humidity => Humidity, humidity_target => HumidityTarget, speed => Speed, speed_fact => SpeedFact, | |
| speed_target => SpeedTarget, | |
| misc => Misc, time => {Year+2000,Month,Day,Hour,Min,0}, day_of_week => Dow, msg => Msg}; | |
| parse2(<<"VZL0",Zone:1/binary>>, [<<VAVMixControlV:1, VAVControlV:3, VAVStateV:4, VAVIcon:8>>, | |
| <<LevelFact:8, LevelTarget:8>>, CO2_]) -> | |
| CO2 = binary_to_integer(CO2_), | |
| VavState = case VAVStateV of | |
| 0 -> disabled; | |
| 1 -> ok; | |
| 2 -> no_link; | |
| 3 -> has_errors | |
| end, | |
| VavControl = case VAVControlV of | |
| 0 -> local_sensor; | |
| 1 -> center; | |
| 2 when VAVMixControlV == 0 -> mixed_local; | |
| 2 when VAVMixControlV == 1 -> mixed_center; | |
| 3 -> co2; | |
| 4 -> local_dry; | |
| 5 -> auto_mix | |
| end, | |
| #{zone => binary_to_integer(Zone), vav_state => VavState, vav_control => VavControl, vav_icon => VAVIcon, | |
| level_target => LevelTarget, level_fact => LevelFact, co2 => CO2}. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment