From bb318d6a969b91be1f3376cbdb3c7579f932e10f Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Thu, 11 Jul 2019 02:01:41 +0300 Subject: [PATCH 01/16] binaries for due-5500 --- compiled/DUE_16u2_reflash/16u2.hex | 273 ++++++++++++++++++++ compiled/DUE_16u2_reflash/reflash16u2DUE.sh | 0 compiled/due-5500/firmware.bin | Bin 119064 -> 119056 bytes 3 files changed, 273 insertions(+) create mode 100644 compiled/DUE_16u2_reflash/16u2.hex mode change 100644 => 100755 compiled/DUE_16u2_reflash/reflash16u2DUE.sh diff --git a/compiled/DUE_16u2_reflash/16u2.hex b/compiled/DUE_16u2_reflash/16u2.hex new file mode 100644 index 0000000..33363e7 --- /dev/null +++ b/compiled/DUE_16u2_reflash/16u2.hex @@ -0,0 +1,273 @@ +:10000000A7C00000C0C00000BEC00000BCC000000F +:10001000BAC00000B8C00000B6C00000B4C0000004 +:10002000B2C00000B0C00000AEC00000C1C40000FB +:1000300085C40000A8C00000A6C00000A4C0000045 +:10004000A2C00000A0C000009EC000009CC0000034 +:100050009AC0000098C0000096C0000021C10000B6 +:1000600092C0000090C000008EC000008CC0000054 +:100070008AC0000088C0000086C0000084C0000064 +:1000800082C0000080C000007EC000007CC0000074 +:100090007AC0000078C000001201100102000008C0 +:1000A00041233D0001000102DC0109023E00020182 +:1000B00000C0320904000001020201000524000111 +:1000C0001004240206052406000107058203080027 +:1000D000FF09040100020A000000070504024000B5 +:1000E00001070583024000010403090432034100B3 +:1000F00072006400750069006E006F002000280027 +:100100007700770077002E006100720064007500B0 +:1001100069006E006F002E0063006300290000007C +:100120002E03410072006400750069006E006F00CC +:1001300020004400750065002000500072006F0030 +:1001400067002E00200050006F0072007400000055 +:1001500011241FBECFEFD2E0DEBFCDBF11E0A0E083 +:10016000B1E0E4EDF0E102C005900D92A831B107D5 +:10017000D9F712E0A8E1B1E001C01D92A833B107A0 +:10018000E1F72BD1A5C73CCF9C01DC01AE57BF4F97 +:10019000ED91FC91119741911196FC93EE9380584B +:1001A0009F4FE817F90711F42D933C939FB7F894EC +:1001B000F901EC57FF4F8081815080839FBF842FCE +:1001C0000895882311F03F9A01C03F9847980895F9 +:1001D000882311F046980895469A0895DF92EF9289 +:1001E000FF920F931F93FC018489813019F08230B4 +:1001F00019F404C010E303C010E001C010E28389C9 +:10020000823009F418608589873031F0883031F008 +:10021000863029F4126003C0146001C01660109289 +:10022000C9001092C8001092CA000785F088E188C2 +:10023000D288202F3F2D4E2D5D2D10921E01203B88 +:1002400084E0380780E0480780E0580719F481E02F +:1002500080931E01CA01B90122E030E040E050E085 +:100260001CD720583B47414E5F4FCA01B901202F90 +:100270003F2D4E2D5D2DEFD6215030403093CD00D7 +:100280002093CC001093CA0082E08093C80088E9D4 +:100290008093C9001F910F91FF90EF90DF90089518 +:1002A0001F920F920FB60F9211242F938F939F934B +:1002B000EF93FF939091CE008EB38430F1F4E091F0 +:1002C000A201F091A3019083E091A201F091A3011A +:1002D000CF0101969093A3018093A201825A91408D +:1002E00021F482E291E0928381839FB7F894809118 +:1002F000A6018F5F8093A6019FBFFF91EF919F9111 +:100300008F912F910F900FBE0F901F901895FC01A9 +:1003100040911A0140931B0180911C0180931D01A3 +:100320008585282F30E02170307020931A01858553 +:1003300090E096958795817080931C0180911E01B5 +:10034000882339F088E790E0909319018093180191 +:100350000895442341F4222331F082E390E0909306 +:10036000190180931801089580E091E00AC680E0A9 +:1003700091E0BDC584B7877F84BF88E10FB6F8944C +:1003800080936000109260000FBE81E01ADF16BCFF +:1003900083E085BD86B58831E8F315BC16BC80E0E6 +:1003A00010DF469A3E9A87E690E09093CD008093C6 +:1003B000CC0086E08093CA001092C80088E1809348 +:1003C000C900539A5A9A8AB180638AB98BB1806303 +:1003D0008BB9A9D284E085BD08950F931F93CF9365 +:1003E000DF93C8DF2FB7F89487EA91E09093280253 +:1003F0008093270290932A02809329022FBF2FB760 +:10040000F89482E291E09093A3018093A2019093EB +:10041000A5018093A4012FBF7894C7EAD1E003E03F +:100420008FB7F89490912B028FBF903809F180E03C +:1004300091E0D3D497FD1CC0E0912702F0912802EF +:100440008083E0912702F0912802CF0101969093DA +:100450002802809327028752924011F4D283C183ED +:100460009FB7F89480912B028F5F80932B029FBFE0 +:100470008FB7F8941091A6018FBFA89903C01136C9 +:1004800008F456C0A89A8091A601882361F05D986F +:1004900000931F0108C082E291E076DE682F80E0C1 +:1004A00091E001D511501123B1F780911F018823EC +:1004B00051F080911F01815080931F0180911F0195 +:1004C000882309F45D9A80912001882351F080915E +:1004D000200181508093200180912001882309F41C +:1004E0005C9A809118019091190118161906E4F48C +:1004F000CC97CD9710F481E001C080E069DE809157 +:100500001801909119010197C29710F481E001C080 +:1005100080E057DE80911801909119010197909326 +:1005200019018093180104C080E052DE80E049DEAA +:100530008FB7F89490912B028FBF992369F087EAC7 +:1005400091E022DE982F8091C80085FFFCCF909328 +:10055000CE005C980093200180E091E095D42AD4ED +:100560005FCFDA01923049F0933061F09130F9F4C5 +:10057000E8E9F0E022E130E01EC0EAEAF0E02EE334 +:1005800030E019C0813049F0813018F0823079F4C0 +:1005900008C0E8EEF0E0849107C0ECEEF0E0849152 +:1005A00003C0E0E2F1E08491282F30E004C0E0E0F5 +:1005B000F0E020E030E0ED93FC93C901089528E0DD +:1005C00030E040E003C04F5F220F331F2817390788 +:1005D000D0F3842F8295807F08958093E9008091E5 +:1005E000EB0081608093EB001092ED006093EC00D3 +:1005F0004093ED008091EE00881F8827881F0895A2 +:100600001092F40090E09093E9001092F0001092A4 +:10061000E8001092ED008091EB008E7F8093EB005C +:100620009F5F953081F708958091300288238CF484 +:1006300003C08EB38823B1F08091E80082FFF9CF28 +:100640008091E8008B778093E80008958EB388232B +:1006500049F08091E80080FFF9CF8091E8008E7723 +:100660008093E800089594E68091EC0080FF05C037 +:100670008091E80080FF05C023C08091E80082FDE2 +:100680001FC08EB3882311F482E008958EB38530A5 +:1006900011F483E008958091EB0085FF02C081E0B2 +:1006A00008958091E10082FFDFCF8091E1008B7F90 +:1006B0008093E100992311F484E008959150D4CF00 +:1006C00080E008959C014091360250913702461710 +:1006D000570718F4F90120E038C06115710511F0D1 +:1006E000AB01F8CF8091E8008E778093E80040E07E +:1006F00050E0F0CF8091E80083FF02C081E00895D0 +:100700008091E80082FD2DC08EB3882381F18EB3E5 +:10071000853079F18091E80080FF17C09091F20058 +:1007200006C081918093F100415050409F5F411578 +:10073000510511F09830A8F320E0983009F421E039 +:100740008091E8008E778093E8004115510591F67D +:10075000222381F606C08EB3882349F08EB38530FC +:1007600041F08091E80082FFF6CF80E0089582E0BA +:10077000089583E008959C0140913602509137021C +:100780004617570710F490E03BC06115710511F052 +:10079000AB01F9CF8091E8008E778093E80040E0CC +:1007A00050E0F1CF8091E80083FF02C081E008951E +:1007B0008091E80082FD30C08EB3882399F18EB31A +:1007C000853091F18091E80080FF1AC08091F2009D +:1007D00009C0F9012F5F3F4FE491E093F1004150D0 +:1007E00050408F5F4115510511F0883090F390E033 +:1007F000883009F491E08091E8008E778093E800DA +:100800004115510579F6992369F606C08EB3882300 +:1008100049F08EB3853041F08091E80082FFF6CF39 +:1008200080E0089582E0089583E008959C016115B9 +:10083000710529F48091E8008B778093E800F90135 +:1008400020C08091E80083FF02C081E008958EB34C +:10085000882339F18EB3853031F18091E80082FF31 +:10086000F0CF06C08091F10081936150704021F07B +:100870008091F2008823B1F78091E8008B77809314 +:10088000E80061157105E9F606C08EB3882349F0CA +:100890008EB3853041F08091E80080FFF6CF80E094 +:1008A000089582E0089583E0089542D044D01EBAAE +:1008B00010922E0210922D0210922C0284E089BD1B +:1008C00089B5826089BD09B400FEFDCF8091D80052 +:1008D000982F9F779093D80080688093D80080915C +:1008E00063008E7F809363008091D8008F7D80931A +:1008F000D8008091E0008E7F8093E0008091E1003D +:100900008E7F8093E1008091E20081608093E2001D +:100910008091E100877F8093E1008091E200886010 +:100920008093E2000895C1DF81E080932F02089553 +:100930001092E20008951092E10008951F920F9224 +:100940000FB60F9211241F932F933F934F935F93F2 +:100950006F937F938F939F93AF93BF93EF93FF9387 +:10096000E9EEF0E0108117701082E0EFF0E0808196 +:10097000877F80837894C3D0F894A9EEB0E01C926E +:10098000E0EFF0E08081886080831C93FF91EF911D +:10099000BF91AF919F918F917F916F915F914F9197 +:1009A0003F912F911F910F900FBE0F901F901895A0 +:1009B0001F920F920FB60F9211242F933F934F93D4 +:1009C0005F936F937F938F939F93AF93BF93EF93B7 +:1009D000FF938091E10080FF1BC08091E20080FFC7 +:1009E00017C08091E1008E7F8093E1008091E2004A +:1009F0008E7F8093E2008091E20080618093E2002C +:100A00008091D80080628093D80019BC1EBAD1D1E1 +:100A10008091E10084FF29C08091E20084FF25C01D +:100A200084E089BD89B5826089BD09B400FEFDCF2F +:100A30008091D8008F7D8093D8008091E1008F7ED7 +:100A40008093E1008091E2008F7E8093E2008091AC +:100A5000E20081608093E20080912E02882311F4ED +:100A600081E001C084E08EBBA4D18091E10083FFCE +:100A700027C08091E20083FF23C08091E100877F3F +:100A80008093E10082E08EBB10922E028091E10003 +:100A90008E7F8093E1008091E2008E7F8093E20060 +:100AA0008091E20080618093E200AADD80E060E056 +:100AB00042E093DD8091F00088608093F00079D16E +:100AC0008091E10082FF0AC08091E20082FF06C0AF +:100AD0008091E1008B7F8093E1006BD1FF91EF91DA +:100AE000BF91AF919F918F917F916F915F914F9146 +:100AF0003F912F910F900FBE0F901F9018951F934D +:100B0000DF93CF93CDB7DEB7AC970FB6F894DEBFC7 +:100B10000FBECDBFE0E3F2E08091F100819322E0CF +:100B2000E833F207C9F78091300230913102353055 +:100B300009F487C0363040F43130C9F1313070F0FB +:100B4000333009F01DC133C0383009F4EFC03930FB +:100B500009F4FEC0363009F013C192C0803821F08C +:100B6000823809F00DC108C090912C0280912D02AD +:100B7000882399F0926011C080913402877080932D +:100B8000E9008091EB0090E025E0969587952A9505 +:100B9000E1F7982F91701092E9008091E800877F2B +:100BA0008093E8009093F1001092F100CAC088236E +:100BB00019F0823009F0E4C090E08F7190700097D6 +:100BC00021F0029709F0DDC00CC080913202813023 +:100BD00009F0D7C010922D02333069F580932D02B1 +:100BE0002AC080913202882331F520913402277087 +:100BF00009F4C7C02093E9008091EB0080FFC1C0D9 +:100C0000333021F48091EB00806213C08091EB00BF +:100C100080618093EB0081E090E002C0880F991F13 +:100C20002A95E2F78093EA001092EA008091EB00A7 +:100C300088608093EB001092E9008091E800877F44 +:100C400083C0882309F09CC0109132028091E80093 +:100C5000877F8093E800E8DC04C08EB3882309F422 +:100C600090C08091E80080FFF8CF812F8F7711F43A +:100C700092E001C093E09EBB80688093E30081C056 +:100C80008058823008F07CC080913202909133020B +:100C900023E08C3D920799F55FB7F894DE01159635 +:100CA0004EE020E030E061E2E42FF0E06093570096 +:100CB000849120FF03C082958F704F5F982F9F70A3 +:100CC000892F805D8A3308F0895F8C9311961C927E +:100CD00011972F5F3F4F12962431310529F75FBFDF +:100CE0008AE28B8383E08C838091E800877F809306 +:100CF000E800CE0103966AE270E0E4DC11C0609186 +:100D00003402AE014F5F5F4F2CDCBC010097C9F18C +:100D10008091E800877F8093E80089819A812BDDAC +:100D20008091E8008B778093E8002BC0803841F5F4 +:100D30008091E800877F8093E80080912E02809365 +:100D4000F1008091E8008E778093E8006DDC19C097 +:100D50008823B1F490913202923098F48091E800A7 +:100D6000877F8093E80090932E025EDC80912E02B4 +:100D7000882311F483E001C084E08EBBF8DA01C05F +:100D8000F3DA8091E80083FF0AC08091EB00806273 +:100D90008093EB008091E800877F8093E800AC9619 +:100DA0000FB6F894DEBF0FBECDBFCF91DF911F917C +:100DB000089508951F938EB3882361F01091E90080 +:100DC0001092E9008091E80083FF01C098DE17705F +:100DD0001093E9001F9108950895FC018EB38430AB +:100DE00021F587859089A189B2890097A105B10570 +:100DF000E1F085818093E9008091E80082FF15C0D1 +:100E00008091F200882319F42FEF3FEF04C0809106 +:100E1000F100282F30E08091F200882341F4809186 +:100E2000E8008B778093E80002C02FEF3FEFC90105 +:100E30000895FC018EB3843011F587859089A189CE +:100E4000B2890097A105B105D1F081818093E900B5 +:100E50008091F2008823A9F09091E8008091E80049 +:100E60008E778093E80095FD0CC0FDDB982F8823DA +:100E700049F48091E8008E778093E80003C092E007 +:100E800001C090E0892F0895FC018EB3843051F4A5 +:100E900087859089A189B2890097A105B10511F0D4 +:100EA000CF01C7CF08951F93FC01162F8EB3843056 +:100EB000D9F487859089A189B2890097A105B105E8 +:100EC00099F081818093E9008091E80085FD08C058 +:100ED0008091E8008E778093E800C5DB882329F4B1 +:100EE0001093F10080E001C082E01F9108950F93FC +:100EF0001F93CF93DF93EC010D96FC0189E0DF0196 +:100F00001D928A95E9F72A813B8109818C8188238A +:100F100011F410E001C014E0C90151DB182B12607C +:100F2000802F61E8412F59DB882329F12E813F81F1 +:100F30000D818885882311F410E001C014E0C901F7 +:100F40003EDB182B1260802F60E8412F46DB8823A0 +:100F500091F02A853B8509858C85882311F410E062 +:100F600001C014E0C9012BDB182B1260802F61EC4B +:100F7000412F33DB01C080E0DF91CF911F910F91B2 +:100F80000895CF93DF93EC018091E80083FF60C068 +:100F9000888190E02091340230913502281739077A +:100FA00009F056C080913102813261F0823220F422 +:100FB000803209F04DC019C0823269F1833209F0E4 +:100FC00047C038C080913002813A09F041C0809119 +:100FD000E800877F8093E800CE010F9667E070E01D +:100FE00071DB8091E8008B7713C0809130028132F1 +:100FF00079F58091E800877F8093E800CE010F9615 +:1010000067E070E013DCCE01E9D88091E8008E77CC +:101010008093E8001DC0809130028132C9F4809134 +:10102000E800877F8093E800809132028D87CE01AF +:101030006ED90DC080913002813251F48091E80068 +:10104000877F8093E800CE0160913202C5DEECDA42 +:10105000DF91CF910895A1E21A2EAA1BBB1BFD01BF +:101060000DC0AA1FBB1FEE1FFF1FA217B307E40787 +:10107000F50720F0A21BB30BE40BF50B661F771FDF +:10108000881F991F1A9469F76095709580959095BF +:101090009B01AC01BD01CF01089597FB092E0526E8 +:1010A0000ED057FD04D0D7DF0AD0001C38F450957D +:1010B0004095309521953F4F4F4F5F4F0895F6F77C +:1010C00090958095709561957F4F8F4F9F4F0895B4 +:0410D000F894FFCFC2 +:1010D400000340000004400000020800000000007B +:0810E4000000000000001400F0 +:00000001FF diff --git a/compiled/DUE_16u2_reflash/reflash16u2DUE.sh b/compiled/DUE_16u2_reflash/reflash16u2DUE.sh old mode 100644 new mode 100755 diff --git a/compiled/due-5500/firmware.bin b/compiled/due-5500/firmware.bin index d001e0eec67429b00a6e8e5ed211cd615a0499ea..8cd10fd805bab442a3b4fb7a77b918f4bb82a638 100644 GIT binary patch delta 19124 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 delta 19155 zcmb_^d3;nw_V2CUJ4q)UvL}S}l8}TXBw-JW+2GQh5CIVZ0ZCZ2BO*aWM8po83T|M5 z=qM^UYN8@^VkSh45gqqoOhkT)%GkI}WEiy&uy3#Ted{L7_?!28@ALk6`Fzejr>ahE zr>ah!I#r!r2lbC1)VqadgJs><24U5u{~d(?_**^5!=u-NUjIMj`Ok7LcMg=x^LUOM zgmVDv+Xi6)0Do@&5e}_32*#rWj7fv|`4tA?2>>sU|NUpd|F7X6&iwBkGk0ib*zX+O zrK#N=NhVLxBw{x{^}bPPHtH=;wO5jP>hZdWMilZc_ck=T#0pzH%Z<3iVrx8`8_erM zj8$!0)~IDq1zlpPlKwzA+7ZQe(N8pKIWGi=#eAfx`-?=qCHqOEkZ00c{s}1Q*nUJK zCW$Ul%YL9HZ6^7d7HG4`5n8J)Aj{}_ZBEX%Ft7LOUiIDDg4#Z-DA@8GdbTEP6^}@X z&k|cULO0Xn+WfKkq1W2d99A*VrepR{!_Z{Mj+CJ8e5ub@^m97}d4qn%m)C|kpZL{NwP3CnC)_#Of`4yoR1$OjWKY9}3du0VC2H7~km`t8$^7Gs80eRb!h{Zk7=u9; ztkJB4_8G0k6OUO$lhfC45o4T}l}KCxW}b@G0G8T>;7>9gqujMQ5mF! zPKi1*S`2TmvVSoI%^iZ~z8TPpE>AR@6ec2R(XvmZScj3#52t!ewbU<^R3oj3)!gk1|VicxWG)s{3QBOYVS%i9o zywcvrMokN!`kMlpmSU@!y)5T-AqG=_Wuu1uDwCEh=P1$4dLqNnj=zUeJ()^7K1Mr^ z(bAZNT(@iyWnUg@9hguWDat#Zx!y=8I~!KC;-k7|lyl1ho*YP#R*N6ig zCRr%Hr8f@~BbHtC3wby8l_>O2{$_~Vy`(Qs%ok(X-;uPSw*+b>mU%(X>8%te+oD@e zNO{d>HYd2DF-jSggZ?OGRC*(MU5LS`Y{aOf$fKN5EoSyiBu`YeYS_L=F(hmVSv(_^ zu@MT!^hUMBv-hR+ms6)Y?1EG|S=Cx1YTRr~Bpa+3gQ*_7!aBM=ntc!yF5f&mwUiIz z^^sxD6!hc42oH^o@Ig&LI9`s&_nAndH<}#*|5LLK3V&53+8foXdMOU2ei{CAKc|)9 z4u9I8ex&biNfQ)$ z98r1;pBsAdu_LkKWXEI(y$lW9u%Qfm??=j<;$ABkY|w}aOcm$a5YwZw za>e>u(1mmo$O<$E;sQH=6AD-K+OcCU?VE?4PRE?GI&b)CzI)EW-cuu6#a=1#2(isV zsCpo@OJ$pZ&}6x~F)G(8s%=h(KB$&-Y&2qO#3j`jwS5c3Y7O+vWLh~S!xJ-)ms#?_SEBbCimix*cV(!p=sKLyP3Ry&Kwb)jtI5p6;IUymh zzSkm7bedTf=tZC>fKCHl19}|j1kfVrF`!MLt3Zzetp|M-=n~Kb^hD4jK?j3E-Z;>O zPID@|jKC-aMj+vr;GON5p`iXjHzrz5C&PINTbyc}nVq1miM8%djNdx|dB0IO26!Lz zOMuq_UjjN1_bcF4&}V>qfXyA;zNzX}-zgMS_S#VT&S1S#u9kAg}DwUj=PG}anKg{M&A7rzod(6dQdQ1)8SUQlLk|abh?L@;a*|uLw z7r2s-g3)p!xt6?3(^Bji|3ImHg?sWrMQdEg1RH6!zu|M}WxCEOKp}z;K8yj5q+lftw&^N&b*R%C1n;P`# zptqiDZ=r`b_aF2^YD#r4gd0^0>rd2(>iRN|p*GEB^>FL&c(A^ncm?~idcJGC2!nvz zj-3BTZ0@`Sb4LuO`bb)vwvHU9$J27itF%9@G{yLoQ78sqQ-@~1Ml_()!@#$b7N@6? zBdfj*R8PRYMXb&IaJye@v z9UqIjOT{s$VW%|4ISN>-w59~qW~szE5=t{97tiFaDL~wMm{-^<>Eet6_o{%+aiPtE z*4RR-!kk`hp&fRCiCvU3ohDcfL-DQj^Y5=PUNlJgXJ7&*cMLli5^O28F{~n}!|oBo z{(x`-!sCK5Y>T|5P4Eh~Xtez#+MbBEPa15y&{J@w^-mgA!We2CIx}mbm)MITjO5uf zFU2fvk%W>c7W5Z7{B0x9v?FxgP`mq-Y;#)Cm09vkW;Uu?hdESxPe?JlWZ#p)Os8Hn zLY;C!OaRp*r#U&ED4Wh3$plfe=Y*69&U=GKcC~z!M>R6KFCRN^45r1SVWT%+{1$@N zvF5PaYj8w6jVx0Z?7SVRqMnO<>x`k%dP{SP-m)B+%YGtyF$K``j8UkhV>62gqsua_ zWC7itIXds%$jx4>7-LhnsP@FMsX+_&XS=9_dL1Hfbm>~sTo&jq!B4%JBgs`XZdi)@ z-Z1R>Rx_eMmsSpYs>;x7brRT5!=)?nA4_D+xBaP(p=jUw$V?`e*uCk_M98EmqH7%j zd}jpu2iO%+wQ`HRDZU5 zc~>(cc)W`oi_zSJ;nhqfyhODYt9xJbOh>DWZ(O4!?1czj8F<*X(hSFvz>W(w81_H= zk6uv64gKPq9}Ub9r%Ectxp5lmdON7`Ry%k|$J&A#G0w~BtB`Ue=a^m>Q(WWO=*!kR z_xl)ZE&GPZzSjbJ9L!*>&eVvH95IP6I9_o6LEJ6wm+G60?2(X~EeUbU`dM^5Dg3PS zY2a<4Wv-_bu{{vl?|cF=8^M$I#6D2I&=bzRz_*2Ph_pQl>gUjI$6ky;BXS7^0=u|H zpzCe%#tkqg1oZnMy4yD1Jt=gZ6m5>O-GLl`3axW&M2^ysW}FvCQ`t8Wc0dISHy``f zezzWFjNLqt*A~#`X~hb5XiJmRg`BBMtt&w72`$HWWa!{vj-i7&j5ti{iWWPf`&OU^ zLE&HEFk0B%q4~&=9Qw#xkAzD>-uyX;X$oC~Zxp@Bo(uQLBlhVTd4WVIJK1Ll?3Yq^ zHH(cGvs@Oj5-}O{g59p^3Z;AL>-KcF(L3HlY{H|wt-6N1dOzP!AQclr z*g@9FzN-UVN@q8#zvc7fq8khMJxq!dfRljJ059Oet485ljsYrcXtOZ6Dgf!Aa{&W| zkML{r#`X$17Exu@?bYu!?3I0E{5Q1=dwI+Vv49UtC|hZ?1r=M)%w&S0QncVGn%aCq z8rn=ta&);mzb=nk$yzJ#d4gZCabtxSk$`Yo=!o+O`g(yb&Phpl7Dmk$K`{UyJ8dxyO!Gw z2n~%aw{OLZE9c8OVX$ka^;aNmY4-d~Im*|P%DP%GIVR#ww(5zfL`Ic7a=90hD zmAUqe`TiX2-*5%^xgnMXYF5DJ%mn_Jw&rHIyCm5zP~GE0J%VjHdZL1!Uk=@FWGmq> zvx+64rps~8XykZNDT5!L?15;f9{6cLJU%Gb$kGF9gkSSpy+ThtM9;^K`>*&~Z$y|M zt}Nnyf2#TBHcU9b$@`qk*s>t1QTEkKM(C9|T9=nYZlr7Ta&zCqfxi4w{i_i0vlekS z>^(l|RtB#7yG1#oXmtTYc_yi{qLJZJ|MtspS zKOG|t!iS=vStC*kwn?*5(`eKr_{TcA4&ErmzN9+8Q$0tr42`lCA?Bh~fbT=JVMNY6 zZSa7LZx6&~b7)y4pen*CXV=KyEXM(t%BE$P1L`8NF|RiRVKu@(1vEv|8+E-Y2w%_L znt^GJf>)I@&x5w?(+y6mf6_A}GN$a6Ui~{Zsd44Gs+{lpg`Qgn2Vgw#+(F^L;BuaZ`}vTSKC zLrWYh4D4|lT4LE-GPiCXRkk}LTLw!%59Mhi57!)Tdl-F83_a+m_-zb9?1tHd`TJrZ+B*lGE0@vd z*6HZ5`mu=b!JvU%>z1n=aHg?`f&w!LTiX_TDt^0)Oi_xz8&1iJu8FAno}gOf2jc1) zEz1s!vcUKYjd3JcHE2X*SSOBxfGgPZ&681y2_h~+p5@%<+*SxlZkNfp5sm_+$q~)S zU;1(pmnvr~^}1(6c+H*|mMD#M#;_ImMzi^HH2X`iP?1NfA`icxSW{8xM2Jk5v%xtF z$Af5Cs?9jd|0!rwcuflLcW@7@(WPuOTF9H!3&(X(u*KI#GfOy4;ZrMopZG_4XSfHg zf{mE0S1baqK{g}Ip!@}4LB#{09|G(K2tsy6Io!e&G`AKW1O5Zxr>7@hb|MIq73o)2GNcPN2cfn*Cf>}q#z#nJ(zRiHE ziQUBs_7mam9}N{McKA)9hnE(4+9;ST#A;*}-6o3wJej^xO}g6x2Oy#}N~|7S}Y6_9R>b7}z#Cz9hH$ z18Ch?_JFJw9oC#{Z6X;RV-yb31Etmsb4Z&P^|jd<58k7pI7fp^gYh+2K!edU zr8(}W-`EHKTaa(_VC#5(-cyP&>kzU(JYt29+1O&(6U$8SE8K0%Z^;9#_uH|XR9Foy zDt0QgUeTwELw7ivZF$hFGh{<+9{iMRF{^$E{+siy&}xO#5o)&G>dbS4b-cXF$+MJ) z2D03UEPwf3mKQ@eDp`s{D+UW6Hdy!~aCZKV^U=^^g)=?0Xpqy0P4gNDFIUeF2Itpi zy0S!}NML)KudB6+!|s1{bWGhdl2tTaSSnm)J0#WD$FhCWKV6etb38LV+-vCXtHC1D zuoojj-o@T1uK{jNC`G%9%?lY?raEKc|8U`CU8!(AMHh_Dbiawy^+Qs9Nt$m4^3K7{ZXr_MWOF#LREv@;c6e=uh&Icv$c>a~o%_6}o8Gi~7Q!;E04&Y6=WHYp;Vr29zD!ANr zPrvgB!~EQdRX7>I*SZAk1bhgX19%y*53n1+=d1>p&*AgH%K%>k8Ue=ug#h<)e0~Ki zgx)&~oDE3mh@BDZjKeg%4oZRFa$XL&L>0SlFr>q6sS3V57c4d{yQrjX2=WUwp=WXu zEV04q+0>Cf*K~Uj_=Gv*5GnAr{$pR?b&qKcNT4 zCb|C{$o^g0$MB`_tX%=??_%GQhbghI1~Pva+aYHtvCjq4e;4}_#9&~Zfn+6ZZ$QOX z1h|Icu^B;&II!wpgr?+;K3|1aO8`Eg!m~z!DLo9jD;HALf4O*6Fo6-<)WpSo*K8>y){w_@7{Gd6FdP&@*REG&RA|Su;H@RCFC#e zorU;^LV9ec^Lp!Wr6|~VxV()NPiwrr*XnY>UeMr7JGC*rWx7*~3p%qcsx=*Jq2E8% zITf?#gg;-b0zT!ha#jHM;eOXDUInT$FvU694dMg;eWuV^i^V=N*>+zSl#sVMn zkHPmN6mhU^43x*2P*m$E1(&(vJtd&LA;HS8cA#gig}AKHv$}AuVsh;E7rTjaklAhrQmw*5XPr2~}_O zW7V>q{@eR2epO{Z)E@&G@E*s6R7Kph&g;E_Ir1voM4g zXna}1q>B>2*fcPszfxQX9PeM~TmVcU+A?t-s7?NP&bh!6ROK9C!9Uw^EfxTyOUepz zD`ebc&J^-y_d05YY=^VbF%(_?MEXJ!%zR+}OPY-D57bkZVmu(Fw-%!n>u6tDf}0{# zgtXJZ!x6ho8YSArbf{Pr^GoS1#Za%Ck(Lb}+)B1)f@iiQ`$$M*FKEKJhH<4h%TO|* zez-FOJlmz=-fU+YsAg#hc-O-1N<=Przm(J}2ues#e+euDtMSA@8o<>z(rvdoQh>Y$vzV)swAwCbD~SCb^a#o;;ci zrQc1qx^r>$s(x~$BaUjHEON%viSQM~?lJGtFh@j>lw3!ibA)K#6Hhg4L4?cKCKo`4 z>7b%ztF!7i?^4)P%Q7*gx8gW$V3tsVV_Vlyr=I;1!PN`+&PRT;kH%=Eh0^Mzlu8Ir)-)J~9>_cRf208RIN*xb~J-IQGjd`YLOCxsJTzWUVArgn+hKSW^ z0^Ss{I8t#6jB;c_Jc}Yi_Rw0rq2HXX>7qB1T0lWt|1^6EDPk;|Fn>=R}jDRFSG2m*zC5USTz{4Tr`OD2XW3IwhrRVL7X;- zlLm3TpGzXuk%}^-yM&%$&nx1;(P9H(EjI|cz&Rxbp%A!hmO&^5?gkzU+*)c7%78Z& z8-%NX7mqavRlvqc24NboXPiNB0-r$oOyC2+?vAXw0(fG__Zsm2s;Dw^dQ^yepu@h1 zwA^)}ANEUNR7nZcsU={pO?M3wcU2{wE^vMAS`O<}SD?o$Fwzq8{St($8@aw4%w?pz zD|5*&w5zf}-;K18?`?X%((ZQ3w3dje^?9C09BMX7=9}4l%?~>AT@Tl&aXF(AOFTPZ z$*NhllD4xs-?gJ=8+Z%l`)l)EsrC2OY(^+YzPC2D{%BXeYkSQmgfr!BGq%@Q>hoP2 z5K5M})^3F-Rj?=2+g%65M@6BatoLuOJo-?Tl{o0(s!H5fT&PNNpNQP3lzL;$Y~*_{ zvI3>bzIk%KYgtVlV!9(sm6&Y*gWhfMzJ+`X0!y$J>ETV`Ub{Ja?+ae(qf}u=W7=%Np3|V40#-4l5OKy;2YwtLT*%g4`R+ zdH2(Bb*6hraD<{i9)>f+Dst@_70QKipvT2_ii5w%(BtMk(P76LygPV@%lWVChAXGf z>o8>`D85C&^#E?D-2}`Hw3~ssA=igJ=WFortA{Uu->oqy>Z54_7#4wX0Wi1p9^zrx z5|09NTjB}ec0e=We!vxf=bf}~YEo{SOp4;qWZ4>A@mTb7IKDL*=4_`F-^w?j{NQ}& zb--!VG%Y2iKYWezYJ`lzI!An~p2Y`i5wg%p)2!9!{L^8x>ERfRZ@mimav-gBGVq1K zBz%QnOpAs!2Fsm%1H2rGX^nqrmOUS~pD)a}pfajwA^Oa;Qui>~2#yCM18I8pm7J$2 z>6Zh1PH;7y8_aNILzJ%uJ}4a47x7&awmNiAV8(|mm`~=eMCjiXJf-2~{1h>^@@;Ha zfQK3)vhTZa3{-%gZ4Ich^v9& z5M2p$R|uGITItYbPJr$()B$kokpY{4k7*Oa_W>RTv;gkM5u>T&-Xo}l9u~8-X1|`f z=t;3I?r5mGQCn~sOI?G>-Aaq6=a8rA-04{)g|3@E-hEq$dp-rWzuApTI5k@u!d1kt zk2Uk^J3$`YNu108jBeAUl?LeJEK?OV5 zY<1lX;XLPWbTmQ$)IULV;RV%kyc)a7;d0tsy5a1C)rso)8F9a zC-l4g4tU@f(Akb8cUxeAldoA9ih)-?a^jqZoH?hlb2oV%;tvL{aq{^xAEsxe$XD!V zexc~K9#<7kYFJDTsYJQlamc*Oi~0oH^x8A$R0J-d5Pw;RvPcv=EAgjsLXrAQS5+xC zFOM{k`;c22gZE#UvVM}Y+*Q}FXV*o9%m1h-Dfw6uaKOt57CN?j#)2c&PuP!&^~kM* zr~ShnB~Inud8VEvcNKv{501|j4sIVjv0e>s_io4GrK;Di==Xx4CeP}y z^r_*K)hc%+%fiuk?J*RCzasd7RWGK2nun`5oj4J0E;TC#JxWXjH6n;-r{V}qwVYr& zZd)`qHH$_m&w5}4;EjQrX~2t9p3P8*KqMeGY;3f5!NZ8|Yw@o11N+7XVv%sP=UR(f z$$a;hXm?GD=@?F6F*eeI1%x-UXKQlY6Qv0_#bHdOMmUe5Or){S(ZFVDOzl`)eQI7( zvt!D;)XLsbHThx*>TC~)jUzAyP(<(q=R)LunV&EcC5u>q`5S`9pWMfvFyXBZ=y9O& zDwHvJ!iBuzzK1=^%>ite@oq_jy~2VATEhdw;5shAquPPTtnHp8N4}VWo%8NMMPrM{ zimMfi9FNDV(Wvl*Y{ruw9j*%aTbD1CN3A!Du_$4v{B3^>ybVIn)y^4;dyy-TtKeSc zSAtxjbCK}ZZ;v2MH8adk{;F>+ym5B8M{HtTovH7oNz+IFF6I$`bDPCua|}mbqddtQ7r582J#W-c5bbbJ z-z!&iagS;`u0++REtn?mKt3jUu{DN8=)$@z{d-|vF~q4JGh1*VX~QgdQ&O zD1ZsTj|4-2GXds~Va|Jx3`3h=iwwp06MCkuXj!q8P^*DC6YGfS8Upv)5VU7kg!lbr zsPTS(9QyyWOe}h@)?q^07WjB|I1%8r1sqGmQ7#ue_jc}rpO*`rYvxMC{|pW8g$A#q ztFA63Tj(=a+oNv|Mtq|}lf8PjlAgFaV{Ck+Q7p%B{uox`gjmjaa?>qGN6F z$F6vA)&|GaX1E@&N8u1?SWcT&p0gt$`z}UEp7D$xJbw-926;AxWna0(4e6loCfYj7n)K|Od?>j% z4IPQNP)c{ius_jnW~I3KVUoW!(Xq$nA&wzv?<&995f6L|E?>;REB%QUJWUP6qI9z- z)=5}Xz~tns$R7&&b_IDoxN&d7)701b!RE@{%XV1h-LSCV1)3J>VDiaqY?vM(4uG@PlFsV=GRq zDRGNI-@X14oS%l&1bv(RLuxbboC8H_6U|`S8_;;;P;FO8_U*?^R^!M#0o~#Amhl0@ zHPJ+bAAo*H1kGPYX8;calp#J9Uxxh^)Q(L`a#UD#Y>bqs^k`g& z_wSHohSP;>z~@78iUu4J;-Nn(@%+i+6QMk4%2ss8(lp^;-I;|NR|7O=T(h9&O`vxH zqHxVvJtxQQJ2s#q_9O0jz^j0xfcF8X08+=0I=xtUXS`#wCmwA)8RSyN%LHsRu?Po) zu?~S9l}!#Vga`dPvBCo}C_EGJq#piV`Nw`@$!n6jx#+kQenh#j5_y~4iY$j9VD8|9 zTk4ndG@`bTpBDL%UB^B?wne8tmFP%9@dtw6fsS`1fPOM)(W_6zVp?N7gAJgg9ehk5 z2_6J(P&Cty;CG<4czKm!9^c;!~qK?;qZWp5AyF`%*e$s7maL~q{>m|?Or~gH-?78-JxSs zf?Vz387ZrQm)6LlC1Ee0x4grRp@F$w5KKd;Q_83#VqSfeEy1C4vpa*OVrq>=4EREF znV6zbJ~_E2AFpu&zVGEkC)diOFwOY!j%#EcmN$0gfCll2aK!VOE%aOw{9EW6@B8P# zX8=C{#vptF_%}cZpu#U|Gyr`^B`&Fzr~iC3w*|D&4*Mfo$MsglH+^2mgrjC;=Cg_y zT6E4g6Ej0z;)D{Ow*+~fKm&IkUs?WbAkUt3Qaetm; zBpQ4xJ$zk${%E+?t*#8@JdC#}TplBS$B$EUmlK`Iy~>?rp;yO zNW8+s&t3$UD-X5g)a%%>h^-F4WP(%Xnj!vYEh7>2T4WdwKY3t1OpnjY$obrFaS>J^ zSzH3klg-M!J)y+8q*PA~)Ul4eOUeAS@kgPbq;77p@un_AQ+TtL<{`|R&KK=A#P0)i z0;VGF9Xfmd%ceOI9e(!pc$MxX_Z}G+l;;OwHCy2%*Rl2fWO&VV>{sdE!sfyoC-J4L zrE3<9H*x{++UlrhK^nQ0e!Re*mG4iKNCwmliz8gDR{ziaIUW^$g4R@lsYy-Omy@e$ z-Sr#il1L$b;bU>duqw&WWx;df>Y?`fJP~TA+uR{ob{>gi3AiW5W{C~O@Z_QM8XraNyGqVXu}jAVEV_9J=se2l6o_0hJ4w=``M>k`fiUQO-HOM>bhso9cZ!PkmA9wpw~F=R$EOpIeF<+YU0q*ro3 zla7x6Olr|{JMX~KgvrPE0TOO5Wzl$lN zKP}HCduh^&byzPCteBRjU1|{40Qf3xio=E9TZW1q2rr=LRy;s9&~-O98kfq#<-6|C zvKwgsjYXzufjqHkaNOs&TW?BJkx_I~BQ@6gli_mJvhV5VjSGy+FtEJP)wJy9(PS=N zb@Qp{QDOU?37#m6mjB>zl61~3m1zy~ zNBsn5@L4#$u2jn3%Iv0xZkbjvA3IT=vOj+%&+pQ*Ss{DdTj@uuw4Yw=x3pne<5=T( zgC8dEqM56nH+u0Ly=k_AmC%n@?I$PN8*hD)kW?DqbT;GfVIl7v{CujG?^Yg?G-k6+ zkTi=kNep|Ln$}RVkser+l=wHC5oOQ{jCv7jbY zXxK+@P@K^w;Fl{VQD}_E0c?LL(+NIUIr$>Td%?|})E%Kc(zKF`o@I^g9$eBQ<$k0z z0B;M~ADmTS=pCZOZbGc}!6@AM{RB$G?hBb}`NB@8>u$@M%}@9rph=$s_^n^Fptqa` z{XO6p0B?!Vn1puBKyEGSbpZ1Rv;*xu`i9WMTde%n2Bp`w|8Sd~7^89iN##J}Z!adf zwDR^$(?O~9YP}d$r0d0xnd!>g4`kNj2X8I?{B4hxO_!eQk19&-;m^pq@GEKlx*y^{ zlC|O<$yQ>Rq$)@_tzmD|tUIivomSpae*K1sP-r|uTKIE{nGs7DcW`KMgOcLCc=K~r zTKp7FgGb`kLy4&B6AHCo>%FAq!!`~3F!E!+`pKuN{tk^wS~W})A#fC$@he7+GF>n_ zU*0j5{JA}AeF`yM9l(hYFAP)hq!WhYokekF0c_+RBO42SX=J0Q`_9d9jgt-bv}$Pn z7cP_tCj2by^DsAu;1K}5ole>C%|=it;K!V zdWdSeSWHIzUr@Oz`X@#AYPQVdFHU3=wb zJ;CoSoLknL_zX?O`I2wic-gz9Q>8iFe(zSB4vVmL$7p=d>?pw3xbqW|+J1WHTE05# z9!w#Q_7x8n6Jn%$ADWY?hs!h>kPff|wqc(0&9M;lLaKfECNhDpdU!QTIP>r^Lhh$e z>{^Jx;CYImKtf(RAMIKLPV2@)+O=0O3gc#8+=t=kwtq4O_PG5mVI)`G%e}adSh{bRK^te4K~r z3D3vzyu=TXn>%s-3VfQjwpC}XhjvlH8TXTX4zE`OzH!hq{OSDI_kum$A=e1Cz_$MFaBx%QsiH)M+oKUH>-9QYij zTU-HOShj8u@^Fu#vbYj^RKtbg0pAOB$7`!HZv$@`c&~82CO37Bf~92L5b!n7gpTpJ zsHyEp%iNBOAmp@Q?sQ8~F0rBjo+L2~wHDFM9aeH<`*R(eNc`f6#dXR0?*gBprJV`n zoAzm)3)L9m1Fxqj5>eHt>Z4p$^?W9#(hpy^BkiZx_bHR)*l?A}0;y#KWcioMy!Ni{ zX9z}mL61ya?F-(TM9BB;dyki^$f@>I@5GVJGjKNSgR{biGlc-BsSZcHX`$bI`C$Mh z?E;734Qw^4Wl1^g9o1fcJ3Z|faLh_(G(-%677 z2PCWSR6A9p)lF440T(9qZ_KBSCn=fG9zOXARPHI<9|GpJpE@<3#D5L`;x~;#{98t$ z0(dXY{Cs9Sj|uh|g;~HGmDo+6m&YIaFN4BsK+HU(?xiO_pJ(E{nSft+Oa)7^cFm*3&_%cN)q3>TY z+rM0r$xAo{;AQ@|5)fWR$ydcnyZ=0xryh7OtsIPfbTHpQ?B=fqYHS_k-Ah})8tC8l zf5n{o>X%IZKRyH~nY;0*fP=;gJ4wL*7x_u>o}*{KrsPulx-*lA$q3BQLHdP%P)W7<8wXcgJk-tGTHMdr6Z6uPL=I^Kp} zY2PlN*AiFf8ZD_M#yb&pKVVzuyE^hBiGKrhkpb$)DX_!1ir&3%lYx8}zX?&((jf!D z^MH3d*BHqpwMlvpdjg;dy^uP)Vu;&B8avC<$umax^COHxx$VEhs{bMGKY9K?g_DK< zu>qZ{vI*8D>+HxO$5g;;^2jHuv~SRFL6GE=z@IBLbH4?Av~xiLc|etB9cdIA07(EN zpgnsaY~2?wA~Ut@UEcrMBgryVCZ}aN4#mwX69ncK1aA+Z9Gb=beP>?@>DL>teFqu< zaC_(R3FN%mQ~{dDjRBN&c1oHypsVFIz3e+Lp_+*H;o)tVJJ5{ zNQQ>Y?c6_utX3Phfp2apTs56Zv&eTkZ41JiJHywJTAlVS&=s9^i^=CIr42_Aeyg*n zo|LP#3cYX5GO||dQlig+B*qKf1BSwZ&J`=jcumq8qq zv~$&Ja^E1m&wo34U%LylV^8P1>&R9;`M%S+iL|SM!_8z8(ejz~{Jtq$NI%)unX{Fg z)DUl{|330b5;5)ja6gfTtY{cFe)*VjOGcHHmKBwZD;hPv^W@WHf%<<+xauG|sMS6+ z#~^I){NY71Nu}+&#vp9!%z23wwP!o&cOc+UbW4D&gF|WbwWW?~#2k36YqnIv(a0bJ5 z=mdm@Ryg;qc%Qszyzy0|PzzYUFX;pF06E%u-~*yJ Date: Sat, 13 Jul 2019 20:18:56 +0300 Subject: [PATCH 02/16] - --- platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 2b3e318..7f7ad35 100644 --- a/platformio.ini +++ b/platformio.ini @@ -20,7 +20,7 @@ env_default = ; mega2560-5100 ; Arduino Mega + Ethernet shield Wiznet 5500 - mega2560-5500 +; mega2560-5500 ; LightHub controller HW revision 2.1 and above (Wiznet 5500 CS on pin 53) ; lighthub21 @@ -29,7 +29,7 @@ env_default = ; due-5100 ; Arduino DUE + Ethernet shield Wiznet 5500 -; due-5500 + due-5500 ; ESP 8266 ; esp8266-wifi From 088a4b039799ebc0bba14436366bd0b19515833a Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Sun, 14 Jul 2019 01:11:23 +0300 Subject: [PATCH 03/16] channels abstraction changed --- lighthub/abstractch.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ lighthub/abstractch.h | 16 ++++++++++++++++ lighthub/abstractin.cpp | 9 +-------- lighthub/abstractin.h | 5 +++-- lighthub/abstractout.h | 12 ++++++++++++ 5 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 lighthub/abstractch.cpp create mode 100644 lighthub/abstractch.h create mode 100644 lighthub/abstractout.h diff --git a/lighthub/abstractch.cpp b/lighthub/abstractch.cpp new file mode 100644 index 0000000..bbb9e62 --- /dev/null +++ b/lighthub/abstractch.cpp @@ -0,0 +1,41 @@ + +#include "abstractch.h" +#include +#include "utils.h" +#include +#include "main.h" + +extern lan_status lanStatus; +extern PubSubClient mqttClient; + +int abstractCh::publish(char* topic, long value, char* subtopic) +{ + char valstr[16]; + printUlongValueToStr(valstr, value); + return publish(topic, valstr,subtopic); +}; + +int abstractCh::publish(char* topic, float value, char* subtopic) +{ + char valstr[16]; + printFloatValueToStr(value, valstr); + return publish(topic, valstr,subtopic); +}; + +int abstractCh::publish(char* topic, char * value, char* subtopic) +{ + char addrstr[MQTT_TOPIC_LENGTH]; + + if (topic) + { + strncpy(addrstr,topic,sizeof(addrstr)); + if (!strchr(addrstr,'/')) setTopic(addrstr,sizeof(addrstr),T_OUT,topic); + strncat(addrstr,subtopic,sizeof(addrstr)); + if (mqttClient.connected() && lanStatus == OPERATION) + { + mqttClient.publish(addrstr, value, true); + return 1; + } + } + +}; diff --git a/lighthub/abstractch.h b/lighthub/abstractch.h new file mode 100644 index 0000000..a223db8 --- /dev/null +++ b/lighthub/abstractch.h @@ -0,0 +1,16 @@ +#pragma once +#include "Arduino.h" + +class abstractCh { +public: + abstractCh(){}; +// virtual int Setup(int addr) = 0; + virtual int Poll() = 0; + +protected: +// Input * in; +int publish(char* topic, long value, char* subtopic = NULL); +int publish(char* topic, float value, char* subtopic = NULL ); +int publish(char* topic, char * value, char* subtopic = NULL); +//friend Input; +}; diff --git a/lighthub/abstractin.cpp b/lighthub/abstractin.cpp index 2461f55..f371c92 100644 --- a/lighthub/abstractin.cpp +++ b/lighthub/abstractin.cpp @@ -31,14 +31,7 @@ int abstractIn::publish(char * value, char* subtopic) aJsonObject *emit = aJson.getObjectItem(in->inputObj, "emit"); if (emit) { - strncpy(addrstr,emit->valuestring,sizeof(addrstr)); - if (!strchr(addrstr,'/')) setTopic(addrstr,sizeof(addrstr),T_OUT,emit->valuestring); - strncat(addrstr,subtopic,sizeof(addrstr)); - if (mqttClient.connected() && lanStatus == OPERATION) - { - mqttClient.publish(addrstr, value, true); - return 1; - } + return publish(emit->valuestring,value,subtopic); } } return 0; diff --git a/lighthub/abstractin.h b/lighthub/abstractin.h index 5d2ca4e..ed24538 100644 --- a/lighthub/abstractin.h +++ b/lighthub/abstractin.h @@ -1,10 +1,11 @@ #pragma once #include "Arduino.h" +#include "abstractch.h" class Input; -class abstractIn { +class abstractIn : public abstractCh{ public: - abstractIn(Input * _in){in=_in;}; + abstractIn(Input * _in):abstractCh(){in=_in;}; virtual int Setup(int addr) = 0; virtual int Poll() = 0; diff --git a/lighthub/abstractout.h b/lighthub/abstractout.h new file mode 100644 index 0000000..22a0bb1 --- /dev/null +++ b/lighthub/abstractout.h @@ -0,0 +1,12 @@ +#pragma once +#include "Arduino.h" + +class Input; +class abstractOut { +public: + abstractOut(Input * _in){in=_in;}; + virtual int Setup(int addr) = 0; + virtual int Poll() = 0; +protected: + +}; From 5c4b1512bbf1755eea06baa4226e0b64409ec56d Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Tue, 16 Jul 2019 22:00:11 +0300 Subject: [PATCH 04/16] abstract ch defs --- lighthub/abstractout.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lighthub/abstractout.h b/lighthub/abstractout.h index 22a0bb1..1453e73 100644 --- a/lighthub/abstractout.h +++ b/lighthub/abstractout.h @@ -1,10 +1,10 @@ #pragma once #include "Arduino.h" -class Input; -class abstractOut { + +class abstractOut : public abstractCh{ public: - abstractOut(Input * _in){in=_in;}; + abstractOut(Input * _in):abstractCh(){in=_in;}; virtual int Setup(int addr) = 0; virtual int Poll() = 0; protected: From a24e56e941b52070011f524163b225d80a0709e4 Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Fri, 19 Jul 2019 01:11:48 +0300 Subject: [PATCH 05/16] generic output channel and first example on SPI LED --- lighthub/abstractch.cpp | 10 +-- lighthub/abstractch.h | 11 ++-- lighthub/abstractin.cpp | 3 +- lighthub/abstractin.h | 2 - lighthub/abstractout.h | 10 +-- lighthub/inputs.cpp | 4 +- lighthub/item.cpp | 89 ++++++++++++++++++-------- lighthub/item.h | 8 ++- lighthub/modules/in_ccs811_hdc1080.cpp | 4 +- lighthub/modules/in_ccs811_hdc1080.h | 4 +- lighthub/modules/out_spiled.cpp | 69 ++++++++++++++++++++ lighthub/modules/out_spiled.h | 16 +++++ 12 files changed, 179 insertions(+), 51 deletions(-) create mode 100644 lighthub/modules/out_spiled.cpp create mode 100644 lighthub/modules/out_spiled.h diff --git a/lighthub/abstractch.cpp b/lighthub/abstractch.cpp index bbb9e62..7c45b55 100644 --- a/lighthub/abstractch.cpp +++ b/lighthub/abstractch.cpp @@ -8,21 +8,21 @@ extern lan_status lanStatus; extern PubSubClient mqttClient; -int abstractCh::publish(char* topic, long value, char* subtopic) +int abstractCh::publishTopic(char* topic, long value, char* subtopic) { char valstr[16]; printUlongValueToStr(valstr, value); - return publish(topic, valstr,subtopic); + return publishTopic(topic, valstr,subtopic); }; -int abstractCh::publish(char* topic, float value, char* subtopic) +int abstractCh::publishTopic(char* topic, float value, char* subtopic) { char valstr[16]; printFloatValueToStr(value, valstr); - return publish(topic, valstr,subtopic); + return publishTopic(topic, valstr,subtopic); }; -int abstractCh::publish(char* topic, char * value, char* subtopic) +int abstractCh::publishTopic(char* topic, char * value, char* subtopic) { char addrstr[MQTT_TOPIC_LENGTH]; diff --git a/lighthub/abstractch.h b/lighthub/abstractch.h index a223db8..bcf27a5 100644 --- a/lighthub/abstractch.h +++ b/lighthub/abstractch.h @@ -4,13 +4,14 @@ class abstractCh { public: abstractCh(){}; -// virtual int Setup(int addr) = 0; + virtual ~abstractCh(){}; virtual int Poll() = 0; + virtual int Setup() =0; + virtual int Anounce () {}; protected: -// Input * in; -int publish(char* topic, long value, char* subtopic = NULL); -int publish(char* topic, float value, char* subtopic = NULL ); -int publish(char* topic, char * value, char* subtopic = NULL); +virtual int publishTopic(char* topic, long value, char* subtopic = NULL); +virtual int publishTopic(char* topic, float value, char* subtopic = NULL ); +virtual int publishTopic(char* topic, char * value, char* subtopic = NULL); //friend Input; }; diff --git a/lighthub/abstractin.cpp b/lighthub/abstractin.cpp index f371c92..3ec1e5d 100644 --- a/lighthub/abstractin.cpp +++ b/lighthub/abstractin.cpp @@ -1,5 +1,6 @@ #include "abstractin.h" +#include "abstractch.h" #include #include "utils.h" #include @@ -31,7 +32,7 @@ int abstractIn::publish(char * value, char* subtopic) aJsonObject *emit = aJson.getObjectItem(in->inputObj, "emit"); if (emit) { - return publish(emit->valuestring,value,subtopic); + return publishTopic(emit->valuestring,value,subtopic); } } return 0; diff --git a/lighthub/abstractin.h b/lighthub/abstractin.h index ed24538..cb857c6 100644 --- a/lighthub/abstractin.h +++ b/lighthub/abstractin.h @@ -6,8 +6,6 @@ class Input; class abstractIn : public abstractCh{ public: abstractIn(Input * _in):abstractCh(){in=_in;}; - virtual int Setup(int addr) = 0; - virtual int Poll() = 0; protected: Input * in; diff --git a/lighthub/abstractout.h b/lighthub/abstractout.h index 1453e73..0e441d6 100644 --- a/lighthub/abstractout.h +++ b/lighthub/abstractout.h @@ -1,12 +1,12 @@ #pragma once #include "Arduino.h" +#include "abstractch.h" - +class Item; class abstractOut : public abstractCh{ public: - abstractOut(Input * _in):abstractCh(){in=_in;}; - virtual int Setup(int addr) = 0; - virtual int Poll() = 0; + abstractOut(Item * _item):abstractCh(){item=_item;}; + virtual int Ctrl(short cmd, short n=0, int * Parameters=NULL, boolean send=true, int suffixCode=0, char* subItem=NULL) =0; protected: - + Item * item; }; diff --git a/lighthub/inputs.cpp b/lighthub/inputs.cpp index 41f49a3..1bfd4ad 100644 --- a/lighthub/inputs.cpp +++ b/lighthub/inputs.cpp @@ -118,12 +118,12 @@ if (!isValid() || (!root)) return; if (inType == IN_CCS811) { in_ccs811 ccs811(this); - ccs811.Setup(pin); + ccs811.Setup(); } else if (inType == IN_HDC1080) { in_hdc1080 hdc1080(this); - hdc1080.Setup(pin); + hdc1080.Setup(); } // TODO rest types setup #endif diff --git a/lighthub/item.cpp b/lighthub/item.cpp index 4660b4e..f6ca397 100644 --- a/lighthub/item.cpp +++ b/lighthub/item.cpp @@ -33,6 +33,8 @@ e-mail anklimov@gmail.com #endif #include +#include "modules/out_spiled.h" + const char ON_P[] PROGMEM = "ON"; const char OFF_P[] PROGMEM = "OFF"; const char REST_P[] PROGMEM = "REST"; @@ -95,8 +97,8 @@ int txt2cmd(char *payload) { int txt2subItem(char *payload) { - int cmd = -1; - if (!payload || !strlen(payload)) return 0; + int cmd = S_NOTFOUND; + if (!payload || !strlen(payload)) return S_NOTFOUND; // Check for command if (strcmp_P(payload, SET_P) == 0) cmd = S_SET; else if (strcmp_P(payload, TEMP_P) == 0) cmd = S_TEMP; @@ -115,6 +117,7 @@ const short defval[4] = {0, 0, 0, 0}; //Type,Arg,Val,Cmd Item::Item(aJsonObject *obj)//Constructor { itemArr = obj; + driver = NULL; Parse(); } @@ -127,18 +130,32 @@ void Item::Parse() { itemType = aJson.getArrayItem(itemArr, I_TYPE)->valueint; itemArg = aJson.getArrayItem(itemArr, I_ARG); itemVal = aJson.getArrayItem(itemArr, I_VAL); + + switch (itemType) + { + case CH_SPILED: + driver = new out_SPILed (this); + break; + } // debugSerial << F(" Item:") << itemArr->name << F(" T:") << itemType << F(" =") << getArg() << endl; + } } + +Item::~Item() +{ + if (driver) delete driver; } Item::Item(char *name) //Constructor { + driver = NULL; if (name && items) itemArr = aJson.getObjectItem(items, name); else itemArr = NULL; Parse(); } + uint8_t Item::getCmd(bool ext) { aJsonObject *t = aJson.getArrayItem(itemArr, I_CMD); if (t) @@ -240,34 +257,50 @@ boolean Item::getEnableCMD(int delta) { #define MAXCTRLPAR 3 - +// myhome/dev/item/subItem int Item::Ctrl(char * payload, boolean send, char * subItem){ if (!payload) return 0; -char* subsubItem = NULL; -int subItemN = 0; -int subsubItemN = 0; +char* suffix = NULL; +//int subItemN = 0; +int suffixCode = 0; bool isSet = false; if (subItem && strlen(subItem)) { -if (subsubItem = strchr(subItem, '/')) +if (suffix = strrchr(subItem, '/')) //Trying to retrieving right part { - *subsubItem = 0; - subsubItem++; - subsubItemN = txt2subItem(subsubItem); + *suffix= 0; //Truncate subItem string + suffix++; + suffixCode = txt2subItem(suffix); + // myhome/dev/item/sub.....Item/suffix } - subItemN = txt2subItem(subItem); - if (subItemN==S_SET || subsubItemN==S_SET) isSet = true; -} else isSet = true; /// To be removed - old compatmode +else + { + suffix = subItem; + suffixCode = txt2subItem(suffix); + if (suffixCode) + subItem = NULL; + // myhome/dev/item/suffix -if (isSet) -{ - int cmd = txt2cmd(payload); - debugSerial< "); } debugSerial<Ctrl(cmd, n, Parameters, send, suffixCode, subItem); + int iaddr = getArg(); HSVstore st; switch (cmd) { @@ -653,7 +690,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int subItemN) while (i) { Item it(i->valuestring); // it.copyPar(itemVal); - it.Ctrl(cmd, n, Par, send,subItemN); //// was true + it.Ctrl(cmd, n, Par, send,suffixCode,subItem); //// was true i = i->next; } //while } //if diff --git a/lighthub/item.h b/lighthub/item.h index e3cd221..8924203 100644 --- a/lighthub/item.h +++ b/lighthub/item.h @@ -18,7 +18,9 @@ e-mail anklimov@gmail.com */ #include "options.h" +#include "abstractout.h" +#define S_NOTFOUND 0 #define S_SET 1 #define S_TEMP 2 #define S_MODE 3 @@ -41,6 +43,7 @@ e-mail anklimov@gmail.com #define CH_VCTEMP 8 //Vacom PID regulator #define CH_VC 9 //Vacom modbus motor regulator #define CH_AC_HAIER 10 //AC Haier +#define CH_SPILED 11 #define CH_WHITE 127// #define CMD_NUM 0 @@ -118,12 +121,15 @@ class Item public: aJsonObject *itemArr, *itemArg,*itemVal; uint8_t itemType; + abstractOut * driver; Item(char * name); Item(aJsonObject * obj); + ~Item(); + boolean isValid (); - virtual int Ctrl(short cmd, short n=0, int * Parameters=NULL, boolean send=true, int subItem=0); + virtual int Ctrl(short cmd, short n=0, int * Parameters=NULL, boolean send=true, int suffixCode=0, char* subItem=NULL); virtual int Ctrl(char * payload, boolean send=true, char * subItem=NULL); int getArg(short n=0); diff --git a/lighthub/modules/in_ccs811_hdc1080.cpp b/lighthub/modules/in_ccs811_hdc1080.cpp index b3aa18f..9ea2aec 100644 --- a/lighthub/modules/in_ccs811_hdc1080.cpp +++ b/lighthub/modules/in_ccs811_hdc1080.cpp @@ -17,7 +17,7 @@ static bool HDC1080ready = false; static bool CCS811ready = false; -int in_ccs811::Setup(int addr) +int in_ccs811::Setup() { if (CCS811ready) {debugSerial<(leds, NUM_LEDS); +return 1; +} + +int out_SPILed::Poll() +{ + FastLED.show(); +return 1; +}; + +int out_SPILed::Ctrl(short cmd, short n, int * Parameters, boolean send, int suffixCode, char* subItem) +{ +int from=0, to=NUM_LEDS-1; + +if (subItem) +{ //Just single LED to control + from=atoi(subItem); + to=from; +} + + for (n=from;n<=to;n++) + { + + switch(cmd) + { + CMD_ON: + leds[n] = CRGB::White; + break; + CMD_OFF: + leds[n] = CRGB::Black; + break; + CMD_NUM: + switch (suffixCode) + { + + S_POWER: + S_VOL: + //leds[n].setBrightness(Parameters[0]); + break; + S_SET: + S_HSV: + leds[n] = CHSV(Parameters[0],Parameters[1],Parameters[2]); + break; + S_RGB: + leds[n] = CRGB(Parameters[0],Parameters[1],Parameters[2]); + break; + } + } + } + FastLED.show(); +return 1; +} + +#endif diff --git a/lighthub/modules/out_spiled.h b/lighthub/modules/out_spiled.h new file mode 100644 index 0000000..b3b0e18 --- /dev/null +++ b/lighthub/modules/out_spiled.h @@ -0,0 +1,16 @@ + +#pragma once +#ifndef SPILED_DISABLE +#include + +class out_SPILed : public abstractOut { +public: + + out_SPILed(Item * _item):abstractOut(_item){}; + int Setup() override; + int Poll() override; + virtual int Ctrl(short cmd, short n=0, int * Parameters=NULL, boolean send=true, int suffixCode=0, char* subItem=NULL) override; + +protected: +}; +#endif From fb643945713371bc72eff718eb8dd30f72c7194f Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Fri, 19 Jul 2019 13:52:52 +0300 Subject: [PATCH 06/16] driver status, setup, stop --- lighthub/abstractch.h | 8 +++++++- lighthub/item.cpp | 29 +++++++++++++++++++++++++++-- lighthub/item.h | 1 + lighthub/main.cpp | 5 +++-- lighthub/modules/out_spiled.cpp | 21 +++++++++++++++++++-- lighthub/modules/out_spiled.h | 4 +++- 6 files changed, 60 insertions(+), 8 deletions(-) diff --git a/lighthub/abstractch.h b/lighthub/abstractch.h index bcf27a5..ed7efae 100644 --- a/lighthub/abstractch.h +++ b/lighthub/abstractch.h @@ -1,13 +1,19 @@ #pragma once #include "Arduino.h" +#define CST_UNKNOWN 0 +#define CST_INITIALIZED 1 + class abstractCh { public: abstractCh(){}; virtual ~abstractCh(){}; virtual int Poll() = 0; - virtual int Setup() =0; + virtual int Setup() =0; //Should initialize hardware and reserve resources virtual int Anounce () {}; + virtual int Stop() {}; //Should free resources + virtual int Status() {return CST_UNKNOWN;} + protected: virtual int publishTopic(char* topic, long value, char* subtopic = NULL); diff --git a/lighthub/item.cpp b/lighthub/item.cpp index f6ca397..7302998 100644 --- a/lighthub/item.cpp +++ b/lighthub/item.cpp @@ -135,15 +135,33 @@ void Item::Parse() { { case CH_SPILED: driver = new out_SPILed (this); + debugSerial<name << F(" T:") << itemType << F(" =") << getArg() << endl; } } +boolean Item::Setup() +{ + +if (driver) + { + if (driver->Status()) driver->Stop(); + driver->Setup(); + return true; + } +else return false; +} + Item::~Item() { - if (driver) delete driver; + if (driver) + { + delete driver; + debugSerial<Ctrl(cmd, n, Parameters, send, suffixCode, subItem); + if (driver) return driver->Ctrl(cmd, n, Parameters, send, suffixCode, subItem); int iaddr = getArg(); HSVstore st; @@ -1222,6 +1240,13 @@ int Item::checkModbusDimmer(int data) { } int Item::Poll() { + + if (driver && driver->Status()) + { + driver->Poll(); + return INTERVAL_POLLING; //TODO refactoring + } + // Legacy polling switch (itemType) { case CH_MODBUS: checkModbusDimmer(); diff --git a/lighthub/item.h b/lighthub/item.h index 8924203..57c5463 100644 --- a/lighthub/item.h +++ b/lighthub/item.h @@ -129,6 +129,7 @@ class Item ~Item(); boolean isValid (); + boolean Setup(); virtual int Ctrl(short cmd, short n=0, int * Parameters=NULL, boolean send=true, int suffixCode=0, char* subItem=NULL); virtual int Ctrl(char * payload, boolean send=true, char * subItem=NULL); diff --git a/lighthub/main.cpp b/lighthub/main.cpp index 1576698..7a561c9 100644 --- a/lighthub/main.cpp +++ b/lighthub/main.cpp @@ -907,7 +907,8 @@ void applyConfig() { while (items && item) if (item->type == aJson_Array && aJson.getArraySize(item)>1) { Item it(item); - if (it.isValid()) { + if (it.isValid() && !it.Setup()) { + //Legacy Setup short inverse = 0; int pin=it.getArg(); if (pin<0) {pin=-pin; inverse = 1;} @@ -1162,7 +1163,7 @@ void saveFlash(short n, char *str) { if (len>MAXFLASHSTR-1) len=MAXFLASHSTR-1; for(int i=0;i(leds, NUM_LEDS); +driverStatus = CST_INITIALIZED; return 1; } +int out_SPILed::Stop() +{ +Serial.println("SPI-LED De-Init"); +FastLED.addLeds(leds, NUM_LEDS); +driverStatus = CST_UNKNOWN; +return 1; +} + +int out_SPILed::Status() +{ +return driverStatus; +} + + int out_SPILed::Poll() { FastLED.show(); @@ -32,7 +49,7 @@ if (subItem) from=atoi(subItem); to=from; } - +debugSerial<Ctrl(cmd, n, Parameters, send, suffixCode, subItem); - int iaddr = getArg(); HSVstore st; switch (cmd) { @@ -409,10 +407,15 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode default: debugSerial<Ctrl(cmd, n, Parameters, send, suffixCode, subItem); + // Legacy code + switch (cmd) { case 0: //no command @@ -790,6 +793,7 @@ int Item::isActive() { if (!isValid()) return -1; //debugSerial<name); + int cmd = getCmd(); @@ -808,6 +812,7 @@ int Item::isActive() { } // Last time was not a command but parameters set. Looking inside + if (driver) return driver->isActive(); st.aslong = getVal(); switch (itemType) { @@ -1244,7 +1249,7 @@ int Item::Poll() { if (driver && driver->Status()) { driver->Poll(); - return INTERVAL_POLLING; //TODO refactoring + return INTERVAL_POLLING; //TODO refactoring } // Legacy polling switch (itemType) { diff --git a/lighthub/modules/out_spiled.cpp b/lighthub/modules/out_spiled.cpp index 850bb45..fbae644 100644 --- a/lighthub/modules/out_spiled.cpp +++ b/lighthub/modules/out_spiled.cpp @@ -5,11 +5,12 @@ #include "options.h" #include "Streaming.h" #include "FastLED.h" +#include "item.h" -#define NUM_LEDS 60 +#define NUM_LEDS 150 #define DATA_PIN 4 -CRGB leds[NUM_LEDS]; +static CRGB leds[NUM_LEDS]; static int driverStatus = CST_UNKNOWN; int out_SPILed::Setup() @@ -23,7 +24,8 @@ return 1; int out_SPILed::Stop() { Serial.println("SPI-LED De-Init"); -FastLED.addLeds(leds, NUM_LEDS); +//FastLED.addLeds(leds, NUM_LEDS); +FastLED.clear(true); driverStatus = CST_UNKNOWN; return 1; } @@ -33,10 +35,14 @@ int out_SPILed::Status() return driverStatus; } +int out_SPILed::isActive() +{ + +} int out_SPILed::Poll() { - FastLED.show(); + //FastLED.show(); return 1; }; @@ -50,36 +56,41 @@ if (subItem) to=from; } debugSerial< Date: Sat, 10 Aug 2019 23:20:23 +0300 Subject: [PATCH 08/16] Split connand and value topics. 1st attempt --- lighthub/item.cpp | 185 +++++++++++++++++++++++++++++++--------------- lighthub/item.h | 21 +++--- lighthub/main.cpp | 4 +- 3 files changed, 140 insertions(+), 70 deletions(-) diff --git a/lighthub/item.cpp b/lighthub/item.cpp index 2f60362..c5dee29 100644 --- a/lighthub/item.cpp +++ b/lighthub/item.cpp @@ -48,6 +48,7 @@ const char TRUE_P[] PROGMEM = "true"; const char FALSE_P[] PROGMEM = "false"; const char SET_P[] PROGMEM = "set"; +const char CMD_P[] PROGMEM = "cmd"; const char TEMP_P[] PROGMEM = "temp"; const char MODE_P[] PROGMEM = "mode"; const char SETPOINT_P[] PROGMEM = "setpoint"; @@ -101,6 +102,7 @@ int txt2subItem(char *payload) { if (!payload || !strlen(payload)) return S_NOTFOUND; // Check for command if (strcmp_P(payload, SET_P) == 0) cmd = S_SET; + else if (strcmp_P(payload, CMD_P) == 0) cmd = S_CMD; else if (strcmp_P(payload, TEMP_P) == 0) cmd = S_TEMP; else if (strcmp_P(payload, MODE_P) == 0) cmd = S_MODE; else if (strcmp_P(payload, SETPOINT_P) == 0) cmd = S_SETPOINT; @@ -282,7 +284,7 @@ int Item::Ctrl(char * payload, boolean send, char * subItem){ char* suffix = NULL; //int subItemN = 0; int suffixCode = 0; -bool isSet = false; +int setCommand = CMD_SET; //default SET behavior now - not turn on channels if (subItem && strlen(subItem)) { @@ -308,7 +310,11 @@ else //if (suffixCode==S_SET) isSet = true; -} else suffixCode=S_SET; /// no subItem - To be removed - old compatmode +} else +{ +suffixCode=S_SET; /// no subItem - To be removed - old compatmode +setCommand = 0; /// Old-style - turn ON by set value +} int cmd = txt2cmd(payload); debugSerial<Ctrl(cmd, n, Parameters, send, suffixCode, subItem); // Legacy code switch (cmd) { - case 0: //no command + case 0: // old style SET - with turning ON + case CMD_SET: // new style SET - w/o turning ON - if (itemType !=CH_THERMO) setCmd(CMD_SET); //prevent ON thermostat by semp set + // if (itemType !=CH_THERMO) setCmd(CMD_SET); //prevent ON thermostat by semp set ???? switch (itemType) { @@ -431,17 +438,25 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode st.s = Par[1]; st.v = Par[2]; setVal(st.aslong); - } else // Just volume passed - { - st.aslong = getVal(); // restore Colour - st.v = Par[0]; // override volume + } else + { //Uncomplete triplet passed + st.aslong = getVal(); // restore CSV triplet + + switch (n) { + case 1: + st.v = Par[0]; // Just volume passed // override volume + break; + case 2: + st.h = Par[0]; + st.s = Par[1]; + } setVal(st.aslong); // Save back Par[0] = st.h; Par[1] = st.s; Par[2] = st.v; n = 3; } - if (send) SendStatus(0,3,Par,true); // Send back triplet ? + if (send) SendStatus(cmd,3,Par,true); // Send back triplet ? break; case CH_GROUP: //Save for groups as well st.h = Par[0]; @@ -454,15 +469,16 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode case CH_DIMMER: case CH_MODBUS: case CH_VCTEMP: - if (send) SendStatus(0, 1, Par,true); // Send back parameter for channel above this line + if (send) SendStatus(cmd, 1, Par,true); // Send back parameter for channel above this line case CH_THERMO: setVal(Par[0]); // Store value }//itemtype - +/* lastctrl = millis(); //last controlled object ond timestamp update lastobj = itemArr; - +*/ + if (cmd == CMD_SET && itemType !=CH_GROUP && !isActive()) return 1; // Parameters are stored, no further action required break; case CMD_XON: @@ -478,7 +494,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode } case CMD_ON: - if (itemType==CH_RGBW && getCmd() == CMD_ON && getEnableCMD(500)) { + if (itemType==CH_RGBW && getCmd() == CMD_ON /*&& getEnableCMD(500) */) { debugSerial< 0) //Stored smthng switch (itemType) { - //case CH_GROUP: + case CH_GROUP: + if (send && !isActive()) SendStatus(cmd); // Just send ON, suppress send back ON of chan already active + break; case CH_RGBW: case CH_RGB: Par[0] = st.h; @@ -1090,6 +1109,7 @@ int Item::checkFM() { { result = node.readHoldingRegisters(2111 - 1, 1); if (result == node.ku8MBSuccess) aJson.addNumberToObject(out, "flt", (int) node.getResponseBuffer(0)); + Ctrl(CMD_OFF); //Shut down /// } else aJson.addNumberToObject(out, "flt", 0); delay(50); @@ -1109,7 +1129,7 @@ int Item::checkFM() { aJson.addNumberToObject(out, "set", fset); aJson.addNumberToObject(out, "t", ftemp = (int) node.getResponseBuffer(1) * a + b); // aJson.addNumberToObject(out,"d", (int) node.getResponseBuffer(2)*a+b); - int pwr = node.getResponseBuffer(3); + int16_t pwr = node.getResponseBuffer(3); if (pwr > 0) aJson.addNumberToObject(out, "pwr", pwr / 10.); else aJson.addNumberToObject(out, "pwr", 0); @@ -1326,51 +1346,100 @@ int Item::SendStatus(short cmd, short n, int *Par, boolean deffered) { return 0; // Todo: Parameters? Now expected that parameters already stored by setVal() } - else { //publush to MQTT - char addrstr[32]; - //char addrbuf[17]; - char valstr[16] = ""; + else { - //strcpy_P(addrstr, outprefix); + char addrstr[48]; + char valstr[16] = ""; + char cmdstr[8] = ""; + bool isParam = false; + bool isCommand = false; + + // Preparing parameters payload ////////// + if (Par) + for (short i = 0; i < n; i++) { + char num[4]; +#ifndef FLASH_64KB + snprintf(num, sizeof(num), "%d", Par[i]); +#else + itoa(Par[i],num,10); +#endif + strncat(valstr, num, sizeof(valstr)); + isParam = true; + if (i != n - 1) { + strcpy(num, ","); + strncat(valstr, num, sizeof(valstr)); + } + } + + // Preparing Command payload ////////////// + switch (cmd) { + case CMD_ON: + case CMD_XON: + strcpy(cmdstr, "ON"); + isCommand = true; + break; + case CMD_OFF: + case CMD_HALT: + strcpy(cmdstr, "OFF"); + isCommand = true; + break; + // TODO send Par + case 0: + case CMD_SET: + break; + default: + debugSerial<name, sizeof(addrstr)); + if (mqttClient.connected() && !ethernetIdleCount) + + if (isCommand) + { + mqttClient.publish(addrstr, cmdstr, true); + debugSerial<")<")<name, sizeof(addrstr)); + strncat(addrstr, "/", sizeof(addrstr)); + strncat_P(addrstr, SET_P, sizeof(addrstr)); + + + debugSerial<")<name, sizeof(addrstr)); + strncat(addrstr, "/", sizeof(addrstr)); + strncat_P(addrstr, CMD_P, sizeof(addrstr)); + + debugSerial<")<")< Date: Tue, 13 Aug 2019 03:37:02 +0300 Subject: [PATCH 09/16] pre-sendStatus routine refactoring commit --- lighthub/abstractout.h | 1 + lighthub/item.cpp | 86 +++++++++++++++++++++++++----------------- lighthub/item.h | 8 ++-- 3 files changed, 57 insertions(+), 38 deletions(-) diff --git a/lighthub/abstractout.h b/lighthub/abstractout.h index b3db579..766027d 100644 --- a/lighthub/abstractout.h +++ b/lighthub/abstractout.h @@ -8,6 +8,7 @@ public: abstractOut(Item * _item):abstractCh(){item=_item;}; virtual int Ctrl(short cmd, short n=0, int * Parameters=NULL, boolean send=true, int suffixCode=0, char* subItem=NULL) =0; virtual int isActive(){return 0;}; + virtual int getDefaultOnVal(){return 100;}; protected: Item * item; }; diff --git a/lighthub/item.cpp b/lighthub/item.cpp index c5dee29..92dfa8c 100644 --- a/lighthub/item.cpp +++ b/lighthub/item.cpp @@ -270,10 +270,11 @@ void analogWrite(int pin, int val) } #endif - +/* boolean Item::getEnableCMD(int delta) { return ((millis() - lastctrl > (unsigned long) delta));// || ((void *)itemArr != (void *) lastobj)); } +*/ #define MAXCTRLPAR 3 @@ -299,7 +300,7 @@ else { suffix = subItem; suffixCode = txt2subItem(suffix); - if (suffixCode) + if (suffixCode) // some known suffix subItem = NULL; // myhome/dev/item/suffix @@ -312,7 +313,7 @@ else //if (suffixCode==S_SET) isSet = true; } else { -suffixCode=S_SET; /// no subItem - To be removed - old compatmode +//suffixCode=S_SET; /// no subItem - To be removed - old compatmode setCommand = 0; /// Old-style - turn ON by set value } @@ -332,15 +333,15 @@ debugSerial<0) cmd = CMD_OFF; else cmd = CMD_ON; break; @@ -426,7 +438,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode case 0: // old style SET - with turning ON case CMD_SET: // new style SET - w/o turning ON - // if (itemType !=CH_THERMO) setCmd(CMD_SET); //prevent ON thermostat by semp set ???? + if (itemType !=CH_THERMO) setCmd(CMD_SET); //prevent ON thermostat by semp set ???? switch (itemType) { @@ -456,33 +468,35 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode Par[2] = st.v; n = 3; } - if (send) SendStatus(cmd,3,Par,true); // Send back triplet ? + if (send) SendStatus(cmd2changeActivity(chActive,cmd),3,Par,true); // Send back triplet ? break; case CH_GROUP: //Save for groups as well st.h = Par[0]; st.s = Par[1]; st.v = Par[2]; setVal(st.aslong); + if (send) SendStatus(cmd2changeActivity(chActive,cmd),n,Par,true); //// Send back triplet for grp? break; case CH_PWM: case CH_VC: case CH_DIMMER: case CH_MODBUS: case CH_VCTEMP: - if (send) SendStatus(cmd, 1, Par,true); // Send back parameter for channel above this line - case CH_THERMO: + case CH_THERMO: ///? wasnt send before/ now will /// setVal(Par[0]); // Store value + if (send) SendStatus(cmd2changeActivity(chActive,cmd), 1, Par,true); // Send back parameter for channel above this line + }//itemtype /* lastctrl = millis(); //last controlled object ond timestamp update lastobj = itemArr; */ - if (cmd == CMD_SET && itemType !=CH_GROUP && !isActive()) return 1; // Parameters are stored, no further action required + if (cmd == CMD_SET && itemType !=CH_GROUP && !chActive>0) return 1; // Parameters are stored, no further action required break; case CMD_XON: - if (!isActive()) //if channel was'nt active before CMD_XON + if (!chActive>0) //if channel was'nt active before CMD_XON { debugSerial<0) return 1; { short params = 0; setCmd(cmd); @@ -542,7 +556,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode Par[1] = st.s; Par[2] = st.v; params = 3; - SendStatus(0, params, Par,true); // Send restored triplet. In any cases + SendStatus(cmd, params, Par,true); // Send restored triplet. In any cases break; case CH_VCTEMP: @@ -552,7 +566,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode case CH_VC: Par[0] = st.aslong; params = 1; - SendStatus(0, params, Par, true); // Send restored parameter, even if send=false - no problem, loop will be supressed at next hop + SendStatus(cmd, params, Par, true); // Send restored parameter, even if send=false - no problem, loop will be supressed at next hop break; case CH_THERMO: Par[0] = st.aslong; @@ -570,7 +584,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode Par[0] = 20; //20 degrees celsium - safe temperature params = 1; setVal(20); - SendStatus(0, params, Par); + SendStatus(cmd, params, Par); break; case CH_RGBW: case CH_RGB: @@ -583,7 +597,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode st.s = Par[1]; st.v = Par[2]; setVal(st.aslong); - SendStatus(0, params, Par,true); + SendStatus(cmd, params, Par,true); break; case CH_RELAY: Par[0] = 100; @@ -595,7 +609,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode Par[0] = 100; params = 1; setVal(100); - SendStatus(0, params, Par); + SendStatus(cmd, params, Par); } } // default handler for (short i = 0; i < params; i++) { @@ -641,7 +655,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode case CMD_HALT: - if (isActive() > 0) { + if (chActive>0) { Par[0] = 0; Par[1] = 0; Par[2] = 0; @@ -1252,7 +1266,7 @@ int Item::checkModbusDimmer(int data) { { if (d) { // Actually turned on if (cmd == CMD_OFF || cmd == CMD_HALT) SendStatus(CMD_ON); //update OH with ON if it was turned off before - SendStatus(0, 1, &d); //update OH with value + SendStatus(CMD_ON, 1, &d); //update OH with value if (cmd != CMD_XON && cmd != CMD_ON) setCmd(CMD_ON); //store command setVal(d); //store value } else { @@ -1311,7 +1325,7 @@ void Item::sendDelayedStatus(){ Par[1] = st.s; Par[2] = st.v; params = 3; - SendStatus(0, params, Par); // Send restored triplet. + SendStatus(cmd, params, Par); // Send restored triplet. break; case CH_VCTEMP: @@ -1324,7 +1338,7 @@ void Item::sendDelayedStatus(){ Par[0] = st.aslong; params = 1; - SendStatus(0, params, Par); // Send restored parameter + SendStatus(cmd, params, Par); // Send restored parameter break; default: SendStatus(cmd); // Just send CMD @@ -1336,14 +1350,11 @@ void Item::sendDelayedStatus(){ #endif int Item::SendStatus(short cmd, short n, int *Par, boolean deffered) { - -/// ToDo: relative patches, configuration int chancmd=getCmd(true); if (deffered) { setCmd(chancmd | CMD_REPORT); debugSerial<")<")<")<")< Date: Tue, 13 Aug 2019 12:30:58 +0300 Subject: [PATCH 10/16] getFlag/setFlag/clearFlag added (cmd ext refactoring) --- lighthub/item.cpp | 225 ++++++++++++++++++++++++---------------------- lighthub/item.h | 25 ++++-- 2 files changed, 135 insertions(+), 115 deletions(-) diff --git a/lighthub/item.cpp b/lighthub/item.cpp index 92dfa8c..c8c497d 100644 --- a/lighthub/item.cpp +++ b/lighthub/item.cpp @@ -176,12 +176,10 @@ Item::Item(char *name) //Constructor } -uint8_t Item::getCmd(bool ext) { +uint8_t Item::getCmd() { aJsonObject *t = aJson.getArrayItem(itemArr, I_CMD); if (t) - if (ext) - return t->valueint; - else return t->valueint & CMD_MASK; + return t->valueint & CMD_MASK; else return -1; } @@ -190,11 +188,42 @@ void Item::setCmd(uint8_t cmdValue) { aJsonObject *itemCmd = aJson.getArrayItem(itemArr, I_CMD); if (itemCmd) { - itemCmd->valueint = cmdValue; + itemCmd->valueint = cmdValue & CMD_MASK | itemCmd->valueint & FLAG_MASK; // Preserve special bits debugSerial<valueint & flag & FLAG_MASK; + } +} + +void Item::setFlag (short flag) +{ + aJsonObject *itemCmd = aJson.getArrayItem(itemArr, I_CMD); + if (itemCmd) + { + itemCmd->valueint |= flag & FLAG_MASK; // Preserve CMD bits + debugSerial<valueint &= CMD_MASK | ~(flag & FLAG_MASK); // Preserve CMD bits + debugSerial<name, sizeof(addrstr)); if (mqttClient.connected() && !ethernetIdleCount) - if (!isParam) //remake + if (!(sendFlags & SEND_PARAMETERS)) { mqttClient.publish(addrstr, cmdstr, true); debugSerial<")<name, sizeof(addrstr)); @@ -1444,7 +1451,7 @@ int Item::SendStatus(short cmd, short n, int *Par, boolean deffered) { } - if (isCommand) + if (sendFlags & SEND_COMMAND) { setTopic(addrstr,sizeof(addrstr),T_OUT); strncat(addrstr, itemArr->name, sizeof(addrstr)); @@ -1454,7 +1461,7 @@ int Item::SendStatus(short cmd, short n, int *Par, boolean deffered) { debugSerial<")< Date: Tue, 13 Aug 2019 23:26:17 +0300 Subject: [PATCH 11/16] HomeKit (HomeBridge) compatible thermostat now. Small bugfixes & cleanup --- lighthub/item.cpp | 181 ++++++++++++++++++++++++++-------------------- lighthub/item.h | 38 +--------- lighthub/main.cpp | 16 +++- 3 files changed, 119 insertions(+), 116 deletions(-) diff --git a/lighthub/item.cpp b/lighthub/item.cpp index c8c497d..e2443fe 100644 --- a/lighthub/item.cpp +++ b/lighthub/item.cpp @@ -47,28 +47,29 @@ const char DECREASE_P[] PROGMEM = "DECREASE"; const char TRUE_P[] PROGMEM = "true"; const char FALSE_P[] PROGMEM = "false"; +const char HEAT_P[] PROGMEM = "HEAT"; +const char COOL_P[] PROGMEM = "COOL"; +const char AUTO_P[] PROGMEM = "AUTO"; + const char SET_P[] PROGMEM = "set"; const char CMD_P[] PROGMEM = "cmd"; -const char TEMP_P[] PROGMEM = "temp"; const char MODE_P[] PROGMEM = "mode"; +/* +const char TEMP_P[] PROGMEM = "temp"; const char SETPOINT_P[] PROGMEM = "setpoint"; const char POWER_P[] PROGMEM = "power"; const char VOL_P[] PROGMEM = "vol"; const char HEAT_P[] PROGMEM = "heat"; +*/ const char HSV_P[] PROGMEM = "hsv"; const char RGB_P[] PROGMEM = "rgb"; const char RPM_P[] PROGMEM = "rpm"; +const char STATE_P[] PROGMEM = "state"; short modbusBusy = 0; extern aJsonObject *pollingItem; - - -//int modbusSet(int addr, uint16_t _reg, int _mask, uint16_t value); - extern PubSubClient mqttClient; extern int8_t ethernetIdleCount; -//extern char outprefix[]; -//const char outprefix[] PROGMEM = OUTTOPIC; static unsigned long lastctrl = 0; static aJsonObject *lastobj = NULL; @@ -77,18 +78,21 @@ int txt2cmd(char *payload) { int cmd = -1; // Check for command - if (strcmp_P(payload, ON_P) == 0) cmd = CMD_ON; + if (*payload == '-' || (*payload >= '0' && *payload <= '9')) cmd = CMD_NUM; + else if (strcmp_P(payload, ON_P) == 0) cmd = CMD_ON; else if (strcmp_P(payload, OFF_P) == 0) cmd = CMD_OFF; else if (strcmp_P(payload, REST_P) == 0) cmd = CMD_RESTORE; else if (strcmp_P(payload, TOGGLE_P) == 0) cmd = CMD_TOGGLE; else if (strcmp_P(payload, HALT_P) == 0) cmd = CMD_HALT; else if (strcmp_P(payload, XON_P) == 0) cmd = CMD_XON; else if (strcmp_P(payload, XOFF_P) == 0) cmd = CMD_XOFF; + else if (strcmp_P(payload, HEAT_P) == 0) cmd = CMD_HEAT; + else if (strcmp_P(payload, COOL_P) == 0) cmd = CMD_COOL; + else if (strcmp_P(payload, AUTO_P) == 0) cmd = CMD_AUTO; else if (strcmp_P(payload, TRUE_P) == 0) cmd = CMD_ON; else if (strcmp_P(payload, FALSE_P) == 0) cmd = CMD_OFF; else if (strcmp_P(payload, INCREASE_P) == 0) cmd = CMD_UP; else if (strcmp_P(payload, DECREASE_P) == 0) cmd = CMD_DN; - else if (*payload == '-' || (*payload >= '0' && *payload <= '9')) cmd = CMD_NUM; //0 else if (*payload == '{') cmd = CMD_JSON; else if (*payload == '#') cmd = CMD_RGB; else if (strncmp_P(payload, HSV_P, strlen (HSV_P)) == 0) cmd = CMD_HSV; @@ -103,14 +107,15 @@ int txt2subItem(char *payload) { // Check for command if (strcmp_P(payload, SET_P) == 0) cmd = S_SET; else if (strcmp_P(payload, CMD_P) == 0) cmd = S_CMD; - else if (strcmp_P(payload, TEMP_P) == 0) cmd = S_TEMP; else if (strcmp_P(payload, MODE_P) == 0) cmd = S_MODE; - else if (strcmp_P(payload, SETPOINT_P) == 0) cmd = S_SETPOINT; - else if (strcmp_P(payload, POWER_P) == 0) cmd = S_POWER; - else if (strcmp_P(payload, VOL_P) == 0) cmd = S_VOL; - else if (strcmp_P(payload, HEAT_P) == 0) cmd = S_HEAT; else if (strcmp_P(payload, HSV_P) == 0) cmd = S_HSV; else if (strcmp_P(payload, RGB_P) == 0) cmd = S_RGB; + /* UnUsed now + else if (strcmp_P(payload, SETPOINT_P) == 0) cmd = S_SETPOINT; + else if (strcmp_P(payload, TEMP_P) == 0) cmd = S_TEMP; + else if (strcmp_P(payload, POWER_P) == 0) cmd = S_POWER; + else if (strcmp_P(payload, VOL_P) == 0) cmd = S_VOL; + else if (strcmp_P(payload, HEAT_P) == 0) cmd = S_HEAT; */ return cmd; } @@ -135,11 +140,13 @@ void Item::Parse() { switch (itemType) { +#ifndef SPILED_DISABLE case CH_SPILED: driver = new out_SPILed (this); // debugSerial<name << F(" T:") << itemType << F(" =") << getArg() << endl; } @@ -292,12 +299,14 @@ void Item::copyPar (aJsonObject *itemV) } */ +/* #if defined(ARDUINO_ARCH_ESP32) void analogWrite(int pin, int val) { //TBD } #endif +*/ /* boolean Item::getEnableCMD(int delta) { @@ -312,7 +321,6 @@ int Item::Ctrl(char * payload, boolean send, char * subItem){ if (!payload) return 0; char* suffix = NULL; -//int subItemN = 0; int suffixCode = 0; int setCommand = CMD_SET; //default SET behavior now - not turn on channels @@ -337,9 +345,6 @@ else suffix = NULL; // myhome/dev/item/subItem } - - -//if (suffixCode==S_SET) isSet = true; } else { //suffixCode=S_SET; /// no subItem - To be removed - old compatmode @@ -385,16 +390,6 @@ debugSerial<0) return 1; // Parameters are stored, no further action required break; @@ -539,6 +538,9 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode if (itemType != CH_GROUP) return -3; } case CMD_ON: + case CMD_COOL: + case CMD_AUTO: + case CMD_HEAT: if (itemType==CH_RGBW && getCmd() == CMD_ON /*&& getEnableCMD(500) */) { debugSerial<0) return 1; { short params = 0; @@ -589,7 +590,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode Par[1] = st.s; Par[2] = st.v; params = 3; - SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED); // Send restored triplet. In any cases + SendStatus(SEND_COMMAND | SEND_PARAMETERS); // Send restored triplet. In any cases break; case CH_VCTEMP: @@ -599,7 +600,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode case CH_VC: Par[0] = st.aslong; params = 1; - SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED); // Send restored parameter, even if send=false - no problem, loop will be supressed at next hop + SendStatus(SEND_COMMAND | SEND_PARAMETERS); // Send restored parameter, even if send=false - no problem, loop will be supressed at next hop break; case CH_THERMO: Par[0] = st.aslong; @@ -636,13 +637,13 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode Par[0] = 100; params = 1; setVal(100); - if (send) SendStatus(SEND_COMMAND); + if (send) SendStatus(SEND_COMMAND | SEND_DEFFERED); break; default: Par[0] = 100; params = 1; setVal(100); - SendStatus(SEND_COMMAND | SEND_PARAMETERS); + SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED); } } // default handler for (short i = 0; i < params; i++) { @@ -771,12 +772,10 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode case CH_GROUP://Group { - //aJsonObject *groupArr= aJson.getArrayItem(itemArr, 1); if (itemArg->type == aJson_Array) { aJsonObject *i = itemArg->child; while (i) { Item it(i->valuestring); -// it.copyPar(itemVal); it.Ctrl(cmd, n, Par, send,suffixCode,subItem); //// was true i = i->next; } //while @@ -868,6 +867,9 @@ int Item::isActive() { switch (cmd) { case CMD_ON: case CMD_XON: + case CMD_AUTO: + case CMD_HEAT: + case CMD_COOL: //debugSerial<<" active"); return 1; case CMD_OFF: @@ -909,7 +911,7 @@ int Item::isActive() { case CH_DIMMER: //Everywhere, in flat VAL case CH_MODBUS: - case CH_THERMO: + // case CH_THERMO: case CH_VC: case CH_VCTEMP: case CH_PWM: @@ -1358,12 +1360,10 @@ int Item::SendStatus(int sendFlags) { return -1; } else { - + sendFlags |= getFlag(SEND_COMMAND | SEND_PARAMETERS); //if some delayed status is pending char addrstr[48]; char valstr[16] = ""; char cmdstr[8] = ""; - // bool isParam = false; - // bool isCommand = false; if (sendFlags & SEND_PARAMETERS) { @@ -1377,15 +1377,9 @@ int Item::SendStatus(int sendFlags) { case CH_RGB: snprintf(valstr, sizeof(valstr), "%d,%d,%d", st.h,st.s,st.v); break; -/* - case CH_VCTEMP: - case CH_PWM: - case CH_DIMMER: //Everywhere, in flat VAL - case CH_MODBUS: - case CH_VC: - case CH_THERMO: - snprintf(valstr, sizeof(valstr), "%d", st.aslong); - break; */ +// case CH_GROUP: +// sendFlags &= ~SEND_PARAMETERS; // Not send params for Group +// break; default: snprintf(valstr, sizeof(valstr), "%d", st.aslong); }//itemtype @@ -1396,18 +1390,18 @@ int Item::SendStatus(int sendFlags) { switch (chancmd) { case CMD_ON: case CMD_XON: - strcpy(cmdstr, "ON"); -// isCommand = true; + case CMD_AUTO: + case CMD_HEAT: + case CMD_COOL: + strcpy_P(cmdstr, ON_P); break; case CMD_OFF: case CMD_HALT: - strcpy(cmdstr, "OFF"); -// isCommand = true; + strcpy_P(cmdstr, OFF_P); break; - // TODO send Par case 0: case CMD_SET: - sendFlags &= ~SEND_COMMAND; + sendFlags &= ~SEND_COMMAND; // Not send command for parametrized req break; default: debugSerial<")<")<")<")<name, sizeof(addrstr)); strncat(addrstr, "/", sizeof(addrstr)); @@ -1460,8 +1480,15 @@ int Item::SendStatus(int sendFlags) { debugSerial<")< nextPollingCheck) { while (pollingItem && !done) { if (pollingItem->type == aJson_Array) { @@ -1762,7 +1763,7 @@ void pollingLoop(void) { } //while }//if } -#endif +//#endif bool isThermostatWithMinArraySize(aJsonObject *item, int minimalArraySize) { return (item->type == aJson_Array) && (aJson.getArrayItem(item, I_TYPE)->valueint == CH_THERMO) && @@ -1770,8 +1771,15 @@ bool isThermostatWithMinArraySize(aJsonObject *item, int minimalArraySize) { } bool thermoDisabledOrDisconnected(aJsonObject *thermoExtensionArray, int thermoStateCommand) { - return thermoStateCommand == CMD_OFF || thermoStateCommand == CMD_HALT || - aJson.getArrayItem(thermoExtensionArray, IET_ATTEMPTS)->valueint == 0; + if (aJson.getArrayItem(thermoExtensionArray, IET_ATTEMPTS)->valueint == 0) return true; + switch (thermoStateCommand) { + case CMD_ON: + case CMD_XON: + case CMD_AUTO: + case CMD_HEAT: + return false; + default: return true; + } } From 90965aad85667dcaa16b02a6dcff733381cc139b Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Wed, 21 Aug 2019 23:20:43 +0300 Subject: [PATCH 12/16] commands are case insensetive now new commands for HVAC/Thermostates core logic fixes: Group channel logic& stats RGBx color change cmd will turn chan on Modbus fm driver shutdown on alarm deadlock fixed hsv bit flag in channels RAM profile added MQTT send empty command for OH fixed ON for thermostat causes HEAT string to stat topic (to be compatible with homekit & home assistant) --- lighthub/item.cpp | 94 ++++++++++++++++++++++++--------- lighthub/item.h | 10 +++- lighthub/modules/out_spiled.cpp | 4 +- 3 files changed, 79 insertions(+), 29 deletions(-) diff --git a/lighthub/item.cpp b/lighthub/item.cpp index e2443fe..63de137 100644 --- a/lighthub/item.cpp +++ b/lighthub/item.cpp @@ -35,24 +35,26 @@ e-mail anklimov@gmail.com #include "modules/out_spiled.h" -const char ON_P[] PROGMEM = "ON"; -const char OFF_P[] PROGMEM = "OFF"; +const char ON_P[] PROGMEM = "ON"; +const char OFF_P[] PROGMEM = "OFF"; const char REST_P[] PROGMEM = "REST"; const char TOGGLE_P[] PROGMEM = "TOGGLE"; const char HALT_P[] PROGMEM = "HALT"; -const char XON_P[] PROGMEM = "XON"; +const char XON_P[] PROGMEM = "XON"; const char XOFF_P[] PROGMEM = "XOFF"; const char INCREASE_P[] PROGMEM = "INCREASE"; const char DECREASE_P[] PROGMEM = "DECREASE"; -const char TRUE_P[] PROGMEM = "true"; -const char FALSE_P[] PROGMEM = "false"; +const char TRUE_P[] PROGMEM = "TRUE"; +const char FALSE_P[] PROGMEM = "FALSE"; const char HEAT_P[] PROGMEM = "HEAT"; const char COOL_P[] PROGMEM = "COOL"; const char AUTO_P[] PROGMEM = "AUTO"; +const char FAN_P[] PROGMEM = "FAN_ONLY"; +const char DRY_P[] PROGMEM = "DRY"; -const char SET_P[] PROGMEM = "set"; -const char CMD_P[] PROGMEM = "cmd"; +const char SET_P[] PROGMEM = "set"; +const char CMD_P[] PROGMEM = "cmd"; const char MODE_P[] PROGMEM = "mode"; /* const char TEMP_P[] PROGMEM = "temp"; @@ -61,9 +63,9 @@ const char POWER_P[] PROGMEM = "power"; const char VOL_P[] PROGMEM = "vol"; const char HEAT_P[] PROGMEM = "heat"; */ -const char HSV_P[] PROGMEM = "hsv"; -const char RGB_P[] PROGMEM = "rgb"; -const char RPM_P[] PROGMEM = "rpm"; +const char HSV_P[] PROGMEM = "hsv"; +const char RGB_P[] PROGMEM = "rgb"; +const char RPM_P[] PROGMEM = "rpm"; const char STATE_P[] PROGMEM = "state"; short modbusBusy = 0; @@ -89,6 +91,8 @@ int txt2cmd(char *payload) { else if (strcmp_P(payload, HEAT_P) == 0) cmd = CMD_HEAT; else if (strcmp_P(payload, COOL_P) == 0) cmd = CMD_COOL; else if (strcmp_P(payload, AUTO_P) == 0) cmd = CMD_AUTO; + else if (strcmp_P(payload, FAN_P) == 0) cmd = CMD_FAN; + else if (strcmp_P(payload, DRY_P) == 0) cmd = CMD_DRY; else if (strcmp_P(payload, TRUE_P) == 0) cmd = CMD_ON; else if (strcmp_P(payload, FALSE_P) == 0) cmd = CMD_OFF; else if (strcmp_P(payload, INCREASE_P) == 0) cmd = CMD_UP; @@ -351,6 +355,9 @@ else setCommand = 0; /// Old-style - turn ON by set value } +int i=0; +while (payload[i]) {payload[i]=toupper(payload[i]);i++;}; + int cmd = txt2cmd(payload); debugSerial<Ctrl(cmd, n, Parameters, send, suffixCode, subItem); // Legacy code - + bool instantON = false; switch (cmd) { case 0: // old style SET - with turning ON + instantON = true; case CMD_SET: // new style SET - w/o turning ON if (itemType !=CH_THERMO) setCmd(CMD_SET); //prevent ON thermostat by semp set ???? @@ -474,6 +483,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode case CH_RGBW: //only if configured VAL array if (!Par[1] && (n == 3)) itemType = CH_WHITE; case CH_RGB: +/* if (n == 3) { // Full triplet passed st.h = Par[0]; st.s = Par[1]; @@ -499,11 +509,34 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode } setCmd(cmd2changeActivity(chActive,cmd)); if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED); // Send back triplet ? - break; + break; */ case CH_GROUP: //Save for groups as well - setVal(Par[n-1]); //Last/only parameter should contain volume - if (chActive && !Par[n-1]) setCmd(CMD_OFF); - if (!chActive && Par[n-1]) setCmd(CMD_ON); + st.aslong = getVal(); + switch (n) + { + case 1: + st.v = Par[0]; //Volume only + Par[0] = st.h; + Par[1] = st.s; + Par[2] = st.v; + n = 3; + break; + case 2: // Just hue and saturation + st.h = Par[0]; + st.s = Par[1]; + Par[2] = st.v; + st.hsv_flag = 1; + n = 3; + break; + case 3: //complete triplet + st.h = Par[0]; + st.s = Par[1]; + st.v = Par[2]; + st.hsv_flag = 1; + } + setVal(st.aslong); + if (chActive && !st.v) setCmd(CMD_OFF); + if (!chActive && st.v) setCmd(CMD_ON); if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED);//// Send back volume for grp? break; case CH_PWM: @@ -523,7 +556,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode }//itemtype - if (cmd == CMD_SET && itemType !=CH_GROUP && !chActive>0) return 1; // Parameters are stored, no further action required + if (getCmd() == CMD_SET && itemType !=CH_GROUP && !chActive>0) return 1; // Parameters are stored, no further action required break; case CMD_XON: @@ -557,8 +590,8 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS ); break; } // if forcewhite - - if (chActive>0) return 1; + + if (chActive>0) {SendStatus(SEND_COMMAND);return 1;} { short params = 0; setCmd(cmd); @@ -1158,7 +1191,9 @@ int Item::checkFM() { { result = node.readHoldingRegisters(2111 - 1, 1); if (result == node.ku8MBSuccess) aJson.addNumberToObject(out, "flt", (int) node.getResponseBuffer(0)); - Ctrl(CMD_OFF); //Shut down /// + modbusBusy=0; + if (isActive()) Ctrl(CMD_OFF); //Shut down /// + modbusBusy=1; } else aJson.addNumberToObject(out, "flt", 0); delay(50); @@ -1331,12 +1366,14 @@ int Item::Poll() { sendDelayedStatus(); return INTERVAL_CHECK_MODBUS; break; - case CH_RGB: //All channels with slider generate too many updates + /* case CH_RGB: //All channels with slider generate too many updates case CH_RGBW: case CH_DIMMER: case CH_PWM: case CH_VCTEMP: case CH_THERMO: + case CH_GROUP:*/ + default: sendDelayedStatus(); } return INTERVAL_POLLING; @@ -1377,9 +1414,12 @@ int Item::SendStatus(int sendFlags) { case CH_RGB: snprintf(valstr, sizeof(valstr), "%d,%d,%d", st.h,st.s,st.v); break; -// case CH_GROUP: -// sendFlags &= ~SEND_PARAMETERS; // Not send params for Group -// break; + case CH_GROUP: + if (st.hsv_flag) + snprintf(valstr, sizeof(valstr), "%d,%d,%d", st.h,st.s,st.v); + else + snprintf(valstr, sizeof(valstr), "%d", st.v); + break; default: snprintf(valstr, sizeof(valstr), "%d", st.aslong); }//itemtype @@ -1413,19 +1453,20 @@ int Item::SendStatus(int sendFlags) { strncat(addrstr, itemArr->name, sizeof(addrstr)); if (mqttClient.connected() && !ethernetIdleCount) - + { if (sendFlags & SEND_PARAMETERS && chancmd != CMD_OFF && chancmd != CMD_HALT) { mqttClient.publish(addrstr, valstr, true); debugSerial<")<")< Date: Thu, 29 Aug 2019 01:06:07 +0300 Subject: [PATCH 13/16] TOGGLE input re-intrrable issue fixed double toggling --- lighthub/inputs.cpp | 4 +++- lighthub/item.cpp | 17 +++++++++++------ lighthub/item.h | 12 +++++++----- lighthub/modules/out_spiled.cpp | 6 +++--- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/lighthub/inputs.cpp b/lighthub/inputs.cpp index 1bfd4ad..15f7af5 100644 --- a/lighthub/inputs.cpp +++ b/lighthub/inputs.cpp @@ -435,13 +435,15 @@ void Input::contactPoll() { if (inType & IN_PUSH_TOGGLE) { if (currentInputState) { //react on leading edge only (change from 0 to 1) store->logicState = !store->logicState; + store->currentValue = currentInputState; onContactChanged(store->logicState); } } else { store->logicState = currentInputState; + store->currentValue = currentInputState; onContactChanged(currentInputState); } - store->currentValue = currentInputState; + // store->currentValue = currentInputState; } } else // no change store->bounce = SAME_STATE_ATTEMPTS; diff --git a/lighthub/item.cpp b/lighthub/item.cpp index 63de137..80c72cf 100644 --- a/lighthub/item.cpp +++ b/lighthub/item.cpp @@ -31,10 +31,11 @@ e-mail anklimov@gmail.com #ifndef MODBUS_DISABLE #include #endif -#include +#include #include "modules/out_spiled.h" +//Commands const char ON_P[] PROGMEM = "ON"; const char OFF_P[] PROGMEM = "OFF"; const char REST_P[] PROGMEM = "REST"; @@ -50,12 +51,14 @@ const char FALSE_P[] PROGMEM = "FALSE"; const char HEAT_P[] PROGMEM = "HEAT"; const char COOL_P[] PROGMEM = "COOL"; const char AUTO_P[] PROGMEM = "AUTO"; -const char FAN_P[] PROGMEM = "FAN_ONLY"; +const char FAN_ONLY_P[] PROGMEM = "FAN_ONLY"; const char DRY_P[] PROGMEM = "DRY"; +// SubTopics const char SET_P[] PROGMEM = "set"; const char CMD_P[] PROGMEM = "cmd"; const char MODE_P[] PROGMEM = "mode"; +const char FAN_P[] PROGMEM = "fan"; /* const char TEMP_P[] PROGMEM = "temp"; const char SETPOINT_P[] PROGMEM = "setpoint"; @@ -65,9 +68,10 @@ const char HEAT_P[] PROGMEM = "heat"; */ const char HSV_P[] PROGMEM = "hsv"; const char RGB_P[] PROGMEM = "rgb"; +/* const char RPM_P[] PROGMEM = "rpm"; const char STATE_P[] PROGMEM = "state"; - +*/ short modbusBusy = 0; extern aJsonObject *pollingItem; extern PubSubClient mqttClient; @@ -91,7 +95,7 @@ int txt2cmd(char *payload) { else if (strcmp_P(payload, HEAT_P) == 0) cmd = CMD_HEAT; else if (strcmp_P(payload, COOL_P) == 0) cmd = CMD_COOL; else if (strcmp_P(payload, AUTO_P) == 0) cmd = CMD_AUTO; - else if (strcmp_P(payload, FAN_P) == 0) cmd = CMD_FAN; + else if (strcmp_P(payload, FAN_ONLY_P) == 0) cmd = CMD_FAN; else if (strcmp_P(payload, DRY_P) == 0) cmd = CMD_DRY; else if (strcmp_P(payload, TRUE_P) == 0) cmd = CMD_ON; else if (strcmp_P(payload, FALSE_P) == 0) cmd = CMD_OFF; @@ -111,9 +115,10 @@ int txt2subItem(char *payload) { // Check for command if (strcmp_P(payload, SET_P) == 0) cmd = S_SET; else if (strcmp_P(payload, CMD_P) == 0) cmd = S_CMD; - else if (strcmp_P(payload, MODE_P) == 0) cmd = S_MODE; +// else if (strcmp_P(payload, MODE_P) == 0) cmd = S_MODE; else if (strcmp_P(payload, HSV_P) == 0) cmd = S_HSV; else if (strcmp_P(payload, RGB_P) == 0) cmd = S_RGB; + else if (strcmp_P(payload, FAN_P) == 0) cmd = S_FAN; /* UnUsed now else if (strcmp_P(payload, SETPOINT_P) == 0) cmd = S_SETPOINT; else if (strcmp_P(payload, TEMP_P) == 0) cmd = S_TEMP; @@ -428,7 +433,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode if (itemType == CH_GROUP && !send) { debugSerial< Date: Thu, 29 Aug 2019 16:35:56 +0300 Subject: [PATCH 14/16] modbus retry issue, core fixes (cold restore issues) --- lighthub/item.cpp | 167 ++++++++++++++++++++++++---------------------- lighthub/item.h | 1 + 2 files changed, 90 insertions(+), 78 deletions(-) diff --git a/lighthub/item.cpp b/lighthub/item.cpp index 80c72cf..553b904 100644 --- a/lighthub/item.cpp +++ b/lighthub/item.cpp @@ -409,6 +409,7 @@ debugSerial< "); + debugSerial<"); } - debugSerial<Ctrl(cmd, n, Parameters, send, suffixCode, subItem); // Legacy code - bool instantON = false; + bool toExecute = (chActive>0); //if channel is already active - unconditionally propogate changes switch (cmd) { case 0: // old style SET - with turning ON - instantON = true; + toExecute = true; case CMD_SET: // new style SET - w/o turning ON - if (itemType !=CH_THERMO) setCmd(CMD_SET); //prevent ON thermostat by semp set ???? + //if (/*itemType !=CH_THERMO && */send) setCmd(CMD_SET); //prevent ON thermostat by semp set ???? switch (itemType) { case CH_RGBW: //only if configured VAL array if (!Par[1] && (n == 3)) itemType = CH_WHITE; case CH_RGB: -/* - if (n == 3) { // Full triplet passed - st.h = Par[0]; - st.s = Par[1]; - st.v = Par[2]; - setVal(st.aslong); - } else - { //Uncomplete triplet passed - st.aslong = getVal(); // restore CSV triplet - - switch (n) { - case 1: - st.v = Par[0]; // Just volume passed // override volume - break; - case 2: - st.h = Par[0]; - st.s = Par[1]; - } - setVal(st.aslong); // Save back - Par[0] = st.h; - Par[1] = st.s; - Par[2] = st.v; - n = 3; - } - setCmd(cmd2changeActivity(chActive,cmd)); - if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED); // Send back triplet ? - break; */ case CH_GROUP: //Save for groups as well st.aslong = getVal(); switch (n) { case 1: + st.v = Par[0]; //Volume only + if (st.hsv_flag) + { Par[0] = st.h; Par[1] = st.s; Par[2] = st.v; - n = 3; + n = 3;} break; case 2: // Just hue and saturation st.h = Par[0]; @@ -540,28 +520,36 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode st.hsv_flag = 1; } setVal(st.aslong); - if (chActive && !st.v) setCmd(CMD_OFF); - if (!chActive && st.v) setCmd(CMD_ON); - if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED);//// Send back volume for grp? + if (toExecute) + { // + if (chActive && !st.v) setCmd(CMD_OFF); + if (!chActive && st.v) setCmd(CMD_ON); + SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED); + } + else SendStatus(SEND_PARAMETERS | SEND_DEFFERED); break; case CH_PWM: case CH_VC: case CH_DIMMER: case CH_MODBUS: - case CH_VCTEMP: - setVal(Par[0]); // Store value - setCmd(cmd2changeActivity(chActive,cmd)); - if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED); // Send back parameter for channel above this line +// setCmd(cmd2changeActivity(chActive,cmd)); + if (toExecute) + { // Not restoring, working + if (chActive && !Par[0]) setCmd(CMD_OFF); + if (!chActive && Par[0]) setCmd(CMD_ON); + SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED); // Send back parameter for channel above this line + } + else SendStatus(SEND_PARAMETERS | SEND_DEFFERED); break; + case CH_VCTEMP: // moved case CH_THERMO: ///? wasnt send before/ now will /// - setVal(Par[0]); // Store value - if (send) SendStatus(SEND_PARAMETERS | SEND_DEFFERED); // Send back parameter for channel above this line - + setVal(Par[0]); // Store value + if (send) SendStatus(SEND_PARAMETERS | SEND_DEFFERED); // Send back parameter for channel above this line }//itemtype - if (getCmd() == CMD_SET && itemType !=CH_GROUP && !chActive>0) return 1; // Parameters are stored, no further action required + if (! toExecute && itemType !=CH_GROUP) return 1; // Parameters are stored, no further action required break; case CMD_XON: @@ -595,11 +583,14 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS ); break; } // if forcewhite - - if (chActive>0) {SendStatus(SEND_COMMAND);return 1;} + setCmd(cmd); + if (chActive>0 && send) + { + SendStatus(SEND_COMMAND); + return 1; + } { short params = 0; - setCmd(cmd); //retrive stored values st.aslong = getVal(); @@ -628,7 +619,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode Par[1] = st.s; Par[2] = st.v; params = 3; - SendStatus(SEND_COMMAND | SEND_PARAMETERS); // Send restored triplet. In any cases + if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS); // ???Send restored triplet. In any cases break; case CH_VCTEMP: @@ -638,7 +629,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode case CH_VC: Par[0] = st.aslong; params = 1; - SendStatus(SEND_COMMAND | SEND_PARAMETERS); // Send restored parameter, even if send=false - no problem, loop will be supressed at next hop + if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS); // ???Send restored parameter, even if send=false - no problem, loop will be supressed at next hop break; case CH_THERMO: Par[0] = st.aslong; @@ -656,7 +647,7 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode Par[0] = 20; //20 degrees celsium - safe temperature params = 1; setVal(20); - SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED); + if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS); //??? // deffered ??? break; case CH_RGBW: case CH_RGB: @@ -669,19 +660,19 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode st.s = Par[1]; st.v = Par[2]; setVal(st.aslong); - SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED); + if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS ); // deffered ??? break; case CH_RELAY: Par[0] = 100; params = 1; setVal(100); - if (send) SendStatus(SEND_COMMAND | SEND_DEFFERED); + if (send) SendStatus(SEND_COMMAND); // deffered ??? break; default: Par[0] = 100; params = 1; setVal(100); - SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED); + if (send) SendStatus(SEND_COMMAND | SEND_PARAMETERS); //??? // deffered ??? } } // default handler for (short i = 0; i < params; i++) { @@ -790,24 +781,12 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode #endif #ifdef _modbus - case CH_MODBUS: { - short numpar=0; - if ((itemArg->type == aJson_Array) && ((numpar = aJson.getArraySize(itemArg)) >= 2)) { - int _addr = aJson.getArrayItem(itemArg, MODBUS_CMD_ARG_ADDR)->valueint; - int _reg = aJson.getArrayItem(itemArg, MODBUS_CMD_ARG_REG)->valueint; - int _mask = -1; - if (numpar >= (MODBUS_CMD_ARG_MASK+1)) _mask = aJson.getArrayItem(itemArg, MODBUS_CMD_ARG_MASK)->valueint; - int _maxval = 0x3f; - if (numpar >= (MODBUS_CMD_ARG_MAX_SCALE+1)) _maxval = aJson.getArrayItem(itemArg, MODBUS_CMD_ARG_MAX_SCALE)->valueint; - int _regType = MODBUS_HOLDING_REG_TYPE; - if (numpar >= (MODBUS_CMD_ARG_REG_TYPE+1)) _regType = aJson.getArrayItem(itemArg, MODBUS_CMD_ARG_REG_TYPE)->valueint; - if (_maxval) modbusDimmerSet(_addr, _reg, _regType, _mask, map(Par[0], 0, 100, 0, _maxval)); - else modbusDimmerSet(_addr, _reg, _regType, _mask, Par[0]); - } - break; - } + case CH_MODBUS: + modbusDimmerSet(Par[0]); + break; #endif + case CH_GROUP://Group { if (itemArg->type == aJson_Array) { @@ -894,7 +873,7 @@ int Item::isActive() { int val = 0; if (!isValid()) return -1; -//debugSerial<name); + debugSerial<name; int cmd = getCmd(); @@ -908,12 +887,12 @@ int Item::isActive() { case CMD_AUTO: case CMD_HEAT: case CMD_COOL: - //debugSerial<<" active"); + debugSerial<type == aJson_Array) { - debugSerial<child; while (i) { Item it(i->valuestring); if (it.isValid() && it.isActive()) { - debugSerial<next; } //while + debugSerial< poll: 0A 03 08 34 00 0A 87 18 */ +#ifdef _modbus +int Item::modbusDimmerSet(uint16_t value) + { + switch (getCmd()) + { + case CMD_OFF: + case CMD_HALT: + value=0; + break; + } + + short numpar=0; + if ((itemArg->type == aJson_Array) && ((numpar = aJson.getArraySize(itemArg)) >= 2)) { + int _addr = aJson.getArrayItem(itemArg, MODBUS_CMD_ARG_ADDR)->valueint; + int _reg = aJson.getArrayItem(itemArg, MODBUS_CMD_ARG_REG)->valueint; + int _mask = -1; + if (numpar >= (MODBUS_CMD_ARG_MASK+1)) _mask = aJson.getArrayItem(itemArg, MODBUS_CMD_ARG_MASK)->valueint; + int _maxval = 0x3f; + if (numpar >= (MODBUS_CMD_ARG_MAX_SCALE+1)) _maxval = aJson.getArrayItem(itemArg, MODBUS_CMD_ARG_MAX_SCALE)->valueint; + int _regType = MODBUS_HOLDING_REG_TYPE; + if (numpar >= (MODBUS_CMD_ARG_REG_TYPE+1)) _regType = aJson.getArrayItem(itemArg, MODBUS_CMD_ARG_REG_TYPE)->valueint; + if (_maxval) modbusDimmerSet(_addr, _reg, _regType, _mask, map(value, 0, 100, 0, _maxval)); + else modbusDimmerSet(_addr, _reg, _regType, _mask, value); + } + } +#endif void Item::mb_fail() { debugSerial< Date: Sat, 14 Sep 2019 06:53:04 +0300 Subject: [PATCH 15/16] group restore/interim fix --- lighthub/item.cpp | 5 +++-- lighthub/main.cpp | 3 ++- lighthub/options.h | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lighthub/item.cpp b/lighthub/item.cpp index 553b904..09fa61c 100644 --- a/lighthub/item.cpp +++ b/lighthub/item.cpp @@ -431,14 +431,15 @@ int Item::Ctrl(short cmd, short n, int *Parameters, boolean send, int suffixCode debugSerial<"); } debugSerial< Date: Sun, 15 Sep 2019 00:44:07 +0300 Subject: [PATCH 16/16] Haier Air Conditioner UART driver added (initial release) some warnings removed --- lighthub/abstractch.cpp | 6 +- lighthub/abstractch.h | 10 +- lighthub/abstractin.cpp | 6 +- lighthub/abstractin.h | 6 +- lighthub/inputs.cpp | 3 +- lighthub/item.cpp | 40 ++-- lighthub/item.h | 34 +-- lighthub/main.cpp | 6 +- lighthub/modules/out_ac.cpp | 433 ++++++++++++++++++++++++++++++++++++ lighthub/modules/out_ac.h | 37 +++ 10 files changed, 535 insertions(+), 46 deletions(-) create mode 100644 lighthub/modules/out_ac.cpp create mode 100644 lighthub/modules/out_ac.h diff --git a/lighthub/abstractch.cpp b/lighthub/abstractch.cpp index 7c45b55..48f3bf8 100644 --- a/lighthub/abstractch.cpp +++ b/lighthub/abstractch.cpp @@ -8,21 +8,21 @@ extern lan_status lanStatus; extern PubSubClient mqttClient; -int abstractCh::publishTopic(char* topic, long value, char* subtopic) +int abstractCh::publishTopic(const char* topic, long value, const char* subtopic) { char valstr[16]; printUlongValueToStr(valstr, value); return publishTopic(topic, valstr,subtopic); }; -int abstractCh::publishTopic(char* topic, float value, char* subtopic) +int abstractCh::publishTopic(const char* topic, float value, const char* subtopic) { char valstr[16]; printFloatValueToStr(value, valstr); return publishTopic(topic, valstr,subtopic); }; -int abstractCh::publishTopic(char* topic, char * value, char* subtopic) +int abstractCh::publishTopic(const char* topic, const char * value, const char* subtopic) { char addrstr[MQTT_TOPIC_LENGTH]; diff --git a/lighthub/abstractch.h b/lighthub/abstractch.h index ed7efae..6c923ed 100644 --- a/lighthub/abstractch.h +++ b/lighthub/abstractch.h @@ -10,14 +10,14 @@ public: virtual ~abstractCh(){}; virtual int Poll() = 0; virtual int Setup() =0; //Should initialize hardware and reserve resources - virtual int Anounce () {}; - virtual int Stop() {}; //Should free resources + virtual int Anounce () {return 0;}; + virtual int Stop() {return 0;}; //Should free resources virtual int Status() {return CST_UNKNOWN;} protected: -virtual int publishTopic(char* topic, long value, char* subtopic = NULL); -virtual int publishTopic(char* topic, float value, char* subtopic = NULL ); -virtual int publishTopic(char* topic, char * value, char* subtopic = NULL); +virtual int publishTopic(const char* topic, long value, const char* subtopic = NULL); +virtual int publishTopic(const char* topic, float value, const char* subtopic = NULL ); +virtual int publishTopic(const char* topic, const char * value, const char* subtopic = NULL); //friend Input; }; diff --git a/lighthub/abstractin.cpp b/lighthub/abstractin.cpp index 3ec1e5d..8956bbb 100644 --- a/lighthub/abstractin.cpp +++ b/lighthub/abstractin.cpp @@ -10,21 +10,21 @@ extern lan_status lanStatus; extern PubSubClient mqttClient; -int abstractIn::publish(long value, char* subtopic) +int abstractIn::publish(long value, const char* subtopic) { char valstr[16]; printUlongValueToStr(valstr, value); return publish(valstr,subtopic); }; -int abstractIn::publish(float value, char* subtopic) +int abstractIn::publish(float value, const char* subtopic) { char valstr[16]; printFloatValueToStr(value, valstr); return publish(valstr,subtopic); }; -int abstractIn::publish(char * value, char* subtopic) +int abstractIn::publish(char * value, const char* subtopic) { char addrstr[MQTT_TOPIC_LENGTH]; if (in) diff --git a/lighthub/abstractin.h b/lighthub/abstractin.h index cb857c6..87f3748 100644 --- a/lighthub/abstractin.h +++ b/lighthub/abstractin.h @@ -9,8 +9,8 @@ public: protected: Input * in; -int publish(long value, char* subtopic = NULL); -int publish(float value, char* subtopic = NULL ); -int publish(char * value, char* subtopic = NULL); +int publish(long value, const char* subtopic = NULL); +int publish(float value, const char* subtopic = NULL ); +int publish(char * value, const char* subtopic = NULL); friend Input; }; diff --git a/lighthub/inputs.cpp b/lighthub/inputs.cpp index 15f7af5..5626e56 100644 --- a/lighthub/inputs.cpp +++ b/lighthub/inputs.cpp @@ -188,6 +188,7 @@ switch (cause) { #endif } } + return 0; } #ifndef COUNTER_DISABLE @@ -226,7 +227,7 @@ void Input::counterPoll() { char addrstr[MQTT_TOPIC_LENGTH]; strncpy(addrstr,emit->valuestring,sizeof(addrstr)); if (!strchr(addrstr,'/')) setTopic(addrstr,sizeof(addrstr),T_OUT,emit->valuestring); - sprintf(valstr, "%d", counterValue); + sprintf(valstr, "%ld", counterValue); if (mqttClient.connected() && !ethernetIdleCount) mqttClient.publish(addrstr, valstr); setNextPollTime(millis() + DHT_POLL_DELAY_DEFAULT); diff --git a/lighthub/item.cpp b/lighthub/item.cpp index 09fa61c..bafdffc 100644 --- a/lighthub/item.cpp +++ b/lighthub/item.cpp @@ -34,6 +34,7 @@ e-mail anklimov@gmail.com #include #include "modules/out_spiled.h" +#include "modules/out_ac.h" //Commands const char ON_P[] PROGMEM = "ON"; @@ -48,11 +49,11 @@ const char DECREASE_P[] PROGMEM = "DECREASE"; const char TRUE_P[] PROGMEM = "TRUE"; const char FALSE_P[] PROGMEM = "FALSE"; -const char HEAT_P[] PROGMEM = "HEAT"; -const char COOL_P[] PROGMEM = "COOL"; -const char AUTO_P[] PROGMEM = "AUTO"; -const char FAN_ONLY_P[] PROGMEM = "FAN_ONLY"; -const char DRY_P[] PROGMEM = "DRY"; +char HEAT_P[] PROGMEM = "HEAT"; +char COOL_P[] PROGMEM = "COOL"; +char AUTO_P[] PROGMEM = "AUTO"; +char FAN_ONLY_P[] PROGMEM = "FAN_ONLY"; +char DRY_P[] PROGMEM = "DRY"; // SubTopics const char SET_P[] PROGMEM = "set"; @@ -81,7 +82,7 @@ static unsigned long lastctrl = 0; static aJsonObject *lastobj = NULL; int txt2cmd(char *payload) { - int cmd = -1; + int cmd = CMD_UNKNOWN; // Check for command if (*payload == '-' || (*payload >= '0' && *payload <= '9')) cmd = CMD_NUM; @@ -115,16 +116,16 @@ int txt2subItem(char *payload) { // Check for command if (strcmp_P(payload, SET_P) == 0) cmd = S_SET; else if (strcmp_P(payload, CMD_P) == 0) cmd = S_CMD; -// else if (strcmp_P(payload, MODE_P) == 0) cmd = S_MODE; + else if (strcmp_P(payload, MODE_P) == 0) cmd = S_MODE; else if (strcmp_P(payload, HSV_P) == 0) cmd = S_HSV; else if (strcmp_P(payload, RGB_P) == 0) cmd = S_RGB; - else if (strcmp_P(payload, FAN_P) == 0) cmd = S_FAN; + else if (strcmp_P(payload, FAN_P) == 0) cmd = S_FAN; /* UnUsed now else if (strcmp_P(payload, SETPOINT_P) == 0) cmd = S_SETPOINT; else if (strcmp_P(payload, TEMP_P) == 0) cmd = S_TEMP; else if (strcmp_P(payload, POWER_P) == 0) cmd = S_POWER; else if (strcmp_P(payload, VOL_P) == 0) cmd = S_VOL; - else if (strcmp_P(payload, HEAT_P) == 0) cmd = S_HEAT; */ + */ return cmd; } @@ -152,7 +153,14 @@ void Item::Parse() { #ifndef SPILED_DISABLE case CH_SPILED: driver = new out_SPILed (this); -// debugSerial<itemArr->name, "ON","/fresh"); + else publishTopic(item->itemArr->name, "OFF","/fresh"); + + ///////////////////////////////// + if (lock_rem == 0x80){ + publishTopic(item->itemArr->name, "ON","/lock"); + } + if (lock_rem == 0x00){ + publishTopic(item->itemArr->name, "OFF","/lock"); + } + ///////////////////////////////// + /* + if (power == 0x01 || power == 0x11){ + publishTopic(item->itemArr->name,"Power", "on"); + } + if (power == 0x00 || power == 0x10){ + publishTopic(item->itemArr->name,"Power", "off"); + } + */ + + Serial.print ("Power="); + Serial.println(power); + + if (power & 0x08) + publishTopic(item->itemArr->name, "ON", "/quiet"); + else publishTopic(item->itemArr->name, "OFF" , "/quiet"); + + + if (power == 3 || power == 2) + publishTopic(item->itemArr->name, "on","/compressor"); + else + publishTopic(item->itemArr->name, "off","/compressor"); + + + publishTopic(item->itemArr->name, (long) swing,"/swing"); + publishTopic(item->itemArr->name, (long) fan_spd,"/fan"); + + ///////////////////////////////// +/* + if (swing == 0x00){ + publishTopic(item->itemArr->name, "off","swing"); + } + if (swing == 0x01){ + publishTopic(item->itemArr->name, "ud","swing"); + } + if (swing == 0x02){ + publishTopic(item->itemArr->name, "lr","swing"); + } + if (swing == 0x03){ + publishTopic(item->itemArr->name, "all","swing"); + } + ///////////////////////////////// + if (fan_spd == 0x00){ + publishTopic(item->itemArr->name, "max","fan"); + } + if (fan_spd == 0x01){ + publishTopic(item->itemArr->name, "mid","fan"); + } + if (fan_spd == 0x02){ + publishTopic(item->itemArr->name, "min","fan"); + } + if (fan_spd == 0x03){ + publishTopic(item->itemArr->name, "auto","fan"); + } + */ + ///////////////////////////////// + + publishTopic(item->itemArr->name,(long)set_tmp,"/set"); + publishTopic(item->itemArr->name, (long)cur_tmp, "/temp"); + //////////////////////////////////// + s_mode[0]='\0'; + + if (mode == 0x00){ + strcpy_P(s_mode,AUTO_P); + } + else if (mode == 0x01){ + strcpy_P(s_mode,COOL_P); + } + else if (mode == 0x02){ + strcpy_P(s_mode,HEAT_P); + } + else if (mode == 0x03){ + strcpy_P(s_mode,FAN_ONLY_P); + } + else if (mode == 0x04){ + strcpy_P(s_mode,DRY_P); + } + + publishTopic(item->itemArr->name, (long) mode, "/mode"); + + if (power & 0x01) + publishTopic(item->itemArr->name, s_mode,"/cmd"); + + else publishTopic(item->itemArr->name, "OFF","/cmd"); + + String raw_str; + char raw[75]; + for (int i=0; i < 37; i++){ + if (data[i] < 10){ + raw_str += "0"; + raw_str += String(data[i], HEX); + } else { + raw_str += String(data[i], HEX); + } + } + raw_str.toUpperCase(); + raw_str.toCharArray(raw,75); + publishTopic(item->itemArr->name, raw,"/raw"); + Serial.println(raw); + +/////////////////////////////////// +} + +byte getCRC(byte req[], size_t size){ + byte crc = 0; + for (int i=2; i < size; i++){ + crc += req[i]; + } + return crc; +} + +void SendData(byte req[], size_t size){ + AC_Serial.write(req, size - 1); + AC_Serial.write(getCRC(req, size-1)); + AC_Serial.flush(); +} + +inline unsigned char toHex( char ch ){ + return ( ( ch >= 'A' ) ? ( ch - 'A' + 0xA ) : ( ch - '0' ) ) & 0x0F; +} + + + +int out_AC::Setup() +{ +Serial.println("AC Init"); +AC_Serial.begin(9600); +driverStatus = CST_INITIALIZED; +return 1; +} + +int out_AC::Stop() +{ +Serial.println("AC De-Init"); + +driverStatus = CST_UNKNOWN; +return 1; +} + +int out_AC::Status() +{ +return driverStatus; +} + +int out_AC::isActive() +{ +return (power & 1); +} + +int out_AC::Poll() +{ + //debugSerial<<"."; + +long now = millis(); + if (now - prevPolling > INTERVAL_AC_POLLING) { + prevPolling = now; + Serial.println ("Polling"); + SendData(qstn, sizeof(qstn)/sizeof(byte)); //Опрос кондиционера + } +delay(100); + if(AC_Serial.available() > 0){ + AC_Serial.readBytes(data, 37); + while(AC_Serial.available()){ + delay(2); + AC_Serial.read(); + } + if (data[36] != inCheck){ + inCheck = data[36]; + InsertData(data, 37); + } + } +return 1; +}; + +int out_AC::Ctrl(short cmd, short n, int * Parameters, boolean send, int suffixCode, char* subItem) +{ + // Some additional Subitems + if (strcmp_P(subItem, LOCK_P) == 0) suffixCode = S_LOCK; + else if (strcmp_P(subItem, SWING_P) == 0) suffixCode = S_SWING; + else if (strcmp_P(subItem, QUIET_P) == 0) suffixCode = S_QUIET; + else if (strcmp_P(subItem, RAW_P) == 0) suffixCode = S_RAW; + + data[B_POWER] = power; + // debugSerial<= 0 && set_tmp <= 30) + { + data[B_SET_TMP] = set_tmp; + } + break; + + case S_CMD: + switch (cmd) + { + case CMD_ON: + data[B_POWER] |= 1; + SendData(on, sizeof(on)/sizeof(byte)); + return 1; + break; + case CMD_OFF: + case CMD_HALT: + data[B_POWER] = 0; + SendData(off, sizeof(off)/sizeof(byte)); + return 1; + break; + case CMD_AUTO: + data[B_MODE] = 0; + data[B_POWER] |= 1; + break; + case CMD_COOL: + data[B_MODE] = 1; + data[B_POWER] |= 1; + break; + case CMD_HEAT: + data[B_MODE] = 2; + data[B_POWER] |= 1; + break; + case CMD_DRY: + data[B_MODE] = 4; + data[B_POWER] |= 1; + break; + case CMD_FAN: + data[B_MODE] = 3; + data[B_POWER] |= 1; + break; + case CMD_UNKNOWN: + return -1; + break; + } + break; + + case S_FAN: + data[B_FAN_SPD] = Parameters[0]; + break; + + case S_MODE: + data[B_MODE] = Parameters[0]; + break; + + case S_LOCK: + switch (cmd) + { + case CMD_ON: + data[B_LOCK_REM] = 80; + break; + case CMD_OFF: + data[B_LOCK_REM] = 0; + break; + } + break; + + case S_SWING: + data[B_SWING] = Parameters[0]; + break; + + case S_QUIET: + switch (cmd) + { + case CMD_ON: + data[B_POWER] |= 8; + break; + case CMD_OFF: + data[B_POWER] &= ~8; + break; + } + + + break; + + case S_RAW: + /* + { + char buf[75]; + char hexbyte[3] = {0}; + strPayload.toCharArray(buf, 75); + int octets[sizeof(buf) / 2] ; + for (int i=0; i < 76; i += 2){ + hexbyte[0] = buf[i] ; + hexbyte[1] = buf[i+1] ; + data[i/2] = (toHex(hexbyte[0]) << 4) | toHex(hexbyte[1]); + + + + AC_Serial.write(data, 37); + AC_Serial.flush(); + + publishTopic("RAW", buf); + } + */ + + break; + + case S_NOTFOUND: + return -1; + + } + +/* + ////////// + if (strTopic == "/myhome/in/Conditioner/Fan_Speed"){ + if (strPayload == "max"){ + data[B_FAN_SPD] = 0; + } + if (strPayload == "mid"){ + data[B_FAN_SPD] = 1; + } + if (strPayload == "min"){ + data[B_FAN_SPD] = 2; + } + if (strPayload == "auto"){ + data[B_FAN_SPD] = 3; + } + } + //////// + if (strTopic == "/myhome/in/Conditioner/Swing"){ + if (strPayload == "off"){ + data[B_SWING] = 0; + } + if (strPayload == "ud"){ + data[B_SWING] = 1; + } + if (strPayload == "lr"){ + data[B_SWING] = 2; + } + if (strPayload == "all"){ + data[B_SWING] = 3; + } + } + //////// + if (strTopic == "/myhome/in/Conditioner/Lock_Remote"){ + if (strPayload == "true"){ + data[B_LOCK_REM] = 80; + } + if (strPayload == "false"){ + data[B_LOCK_REM] = 0; + } + } + //////// + if (strTopic == "/myhome/in/Conditioner/Power"){ + if (strPayload == "off" || strPayload == "false" || strPayload == "0"){ + SendData(off, sizeof(off)/sizeof(byte)); + return; + } + if (strPayload == "on" || strPayload == "true" || strPayload == "1"){ + SendData(on, sizeof(on)/sizeof(byte)); + return; + } + if (strPayload == "quiet"){ + data[B_POWER] = 9; + } + } + */ + //////// + //if (strTopic == "/myhome/in/Conditioner/RAW") + + data[B_CMD] = 0; + data[9] = 1; + data[10] = 77; + data[11] = 95; + SendData(data, sizeof(data)/sizeof(byte)); + return 1; +} + + + +#endif diff --git a/lighthub/modules/out_ac.h b/lighthub/modules/out_ac.h new file mode 100644 index 0000000..9d1d123 --- /dev/null +++ b/lighthub/modules/out_ac.h @@ -0,0 +1,37 @@ + +#pragma once +#ifndef AC_DISABLE +#include + +#define LEN_B 37 +#define B_CUR_TMP 13 //Текущая температура +#define B_CMD 17 // 00-команда 7F-ответ ??? +#define B_MODE 23 //04 - DRY, 01 - cool, 02 - heat, 00 - smart 03 - вентиляция +#define B_FAN_SPD 25 //Скорость 02 - min, 01 - mid, 00 - max, 03 - auto +#define B_SWING 27 //01 - верхний и нижний предел вкл. 00 - выкл. 02 - левый/правый вкл. 03 - оба вкл +#define B_LOCK_REM 28 //80 блокировка вкл. 00 - выкл +#define B_POWER 29 //on/off 01 - on, 00 - off (10, 11)-Компрессор??? 09 - QUIET +#define B_FRESH 31 //fresh 00 - off, 01 - on +#define B_SET_TMP 35 //Установленная температура + +#define S_LOCK S_ADDITIONAL+1 +#define S_QUIET S_ADDITIONAL+2 +#define S_SWING S_ADDITIONAL+3 +#define S_RAW S_ADDITIONAL+4 + +extern void modbusIdle(void) ; +class out_AC : public abstractOut { +public: + + out_AC(Item * _item):abstractOut(_item){}; + int Setup() override; + int Poll() override; + int Stop() override; + int Status() override; + int isActive() override; + int Ctrl(short cmd, short n=0, int * Parameters=NULL, boolean send=true, int suffixCode=0, char* subItem=NULL) override; + +protected: + void InsertData(byte data[], size_t size); +}; +#endif