Browse Source

initial check-in

FloKra 3 years ago
commit
fb4468bf16
36 changed files with 7639 additions and 0 deletions
  1. 967 0
      Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter.ino.hex
  2. 244 0
      Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/DualS0ImpCounter.ino
  3. 127 0
      Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/counterFunctions.ino
  4. 60 0
      Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/eeprom_functions.ino
  5. 232 0
      Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/eeprom_storeRetrieveConfig.ino
  6. 290 0
      Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/eeprom_storeRetrieveCounters.ino
  7. 23 0
      Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/impulseInputs.ino
  8. 30 0
      Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/powerGood.ino
  9. 26 0
      Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/resetForFlashing.ino
  10. 590 0
      Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/serialControl.ino
  11. 201 0
      Hardware/README.md
  12. 164 0
      Hardware/Schematics/FloKra_Modules.pretty/ArduinoProMini_V2wCrystal_allHeaders.kicad_mod
  13. 153 0
      Hardware/Schematics/FloKra_Modules.pretty/ArduinoProMini_noAdditionalHeaders.kicad_mod
  14. 254 0
      Hardware/Schematics/ImpCounter-cache.lib
  15. 1417 0
      Hardware/Schematics/ImpCounter.kicad_pcb
  16. 33 0
      Hardware/Schematics/ImpCounter.pro
  17. 549 0
      Hardware/Schematics/ImpCounter.sch
  18. 21 0
      Hardware/Schematics/Modules-FloKra.bck
  19. 15 0
      Hardware/Schematics/Modules-FloKra.dcm
  20. 108 0
      Hardware/Schematics/Modules-FloKra.lib
  21. 463 0
      Hardware/Schematics/fp-info-cache
  22. 3 0
      Hardware/Schematics/fp-lib-table
  23. BIN
      NodeRED-UI/NodeRED_UI.png
  24. 612 0
      NodeRED-UI/NodeRED_flow.json
  25. BIN
      NodeRED-UI/NodeRED_flow.png
  26. 15 0
      NodeRED-UI/README.md
  27. 66 0
      Notes/Arduino_Impulszaehler_DE.txt
  28. 54 0
      README.md
  29. 264 0
      S0Meters_py/README.md
  30. 61 0
      S0Meters_py/controlarduino.py
  31. 7 0
      S0Meters_py/flasharduino.sh
  32. 38 0
      S0Meters_py/s0meters.ini
  33. 487 0
      S0Meters_py/s0meters.py
  34. 13 0
      S0Meters_py/s0meters.service
  35. 38 0
      S0Meters_py/s0meters.yml
  36. 14 0
      S0Meters_py/s0meters_influxdb.yml

+ 967 - 0
Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter.ino.hex

@@ -0,0 +1,967 @@
+:100000000C94D1040C94F9040C94F9040C94F904A4
+:100010000C94F9040C94F9040C94F9040C94F9046C
+:100020000C94F9040C94F9040C94F9040C94F9045C
+:100030000C94F9040C94F9040C94F9040C94F9044C
+:100040000C94D3150C94F9040C94A1150C947B1505
+:100050000C94F9040C94F9040C94F9040C94F9042C
+:100060000C94F9040C94F9042C20226454696D65F5
+:10007000223A002C2022696D7050657255223A0098
+:100080002C202272656164696E67223A007B2243EC
+:10009000223A0020746F2000454550524F4D202DCC
+:1000A00020666F726D617474696E6720617265613C
+:1000B0002066726F6D20002C2073617665496E7426
+:1000C0003D002C206E6F496D70546F75743D003A81
+:1000D00020696D70506572556E69743D00434F4ED6
+:1000E00046204300534156494E4720474C4F42411A
+:1000F0004C20434F4E46494700494E464F3A205305
+:10010000617665642063757272656E7420726561D4
+:1001100064696E6720746F20454550524F4D2E0024
+:100120002C206E4F66667365743D002C206F6666EA
+:100130007365743D002C20645365743D002C20775A
+:10014000436F756E743D003A20646174613D0049EF
+:100150004E464F3A207072696E74696E67207374F0
+:100160006F72656420696D70756C736520636F755F
+:100170006E746572206F66204300494E464F3A20E8
+:10018000726573746F72656420696D70756C7365E8
+:1001900020636F756E746572206F662043004E4F4A
+:1001A0005448494E4720464F554E44202D20454542
+:1001B00050524F4D2061726561207365656D7320EB
+:1001C000656D70747920666F7220430064536574A6
+:1001D000096F66667365740961646472097743091F
+:1001E0006C774309646174610976616C69640074B9
+:1001F0007279696E6720746F20726573746F7265AF
+:10020000206C61737420696D70756C736573206305
+:100210006F756E7420666F72204300494E464F3AE8
+:100220002073617665642063757272656E742070E8
+:10023000756C73657320636F756E7420746F2045E1
+:100240004550524F4D002C20645365743D002C20C6
+:100250006F66667365743D002C2077436F756E740E
+:100260003D002020646174613D0073746F726543CA
+:10027000757272656E74496D70756C7365733A2032
+:100280004300736176656420616C6C206461746105
+:100290002C20726573657474696E6720696E200026
+:1002A00041444452093009310932093309340935CE
+:1002B0000936093700454550524F4D2D4461746150
+:1002C0003A002C20707772476F6F643D00504F5793
+:1002D00045523A20707772437572723D002C20703F
+:1002E0007772476F6F643D002C20646562526563CE
+:1002F0006F763D002C206465626F756E63653D000E
+:10030000434F4E4620474C4F423A20646562756722
+:100310006C6576656C3D0020636F6E6669672027AB
+:100320006E6F496D70546F75742720696E76616CBD
+:1003300069642120446964206E6F7420736176655E
+:100340002E005741524E494E473A204300202D205F
+:100350006E6F496D70546F75743D00534156494E30
+:100360004720430020636F6E66696720276E6F49E0
+:100370006D70546F75742720696E76616C696421A5
+:1003800020446964206E6F7420736176652E005777
+:1003900041524E494E473A204300202D206E6F496E
+:1003A0006D70546F75743D00534156494E4720435C
+:1003B0000020636F6E6669672027696D70506572F3
+:1003C000556E69742720696E76616C6964212044DA
+:1003D0006964206E6F7420736176652E00574152F8
+:1003E0004E494E473A204300202D20696D705065DC
+:1003F00072556E69743D00534156494E4720430083
+:10040000554E4B4E4F574E20434F4D4D414E443A63
+:100410002027006F7574206F662072616E676520FB
+:10042000302D31353030300077436F756E74204396
+:1004300000494E464F3A20736574206E65772072EE
+:10044000656164696E673A2000494E464F3A2073F1
+:100450006574206E657720696D70756C7365733A8D
+:100460002000494E464F3A20736574206E65772010
+:1004700072656164696E673A20004552524F523A84
+:1004800020696E76616C696420646563696D616C76
+:100490007320666F722073657420696D7050657289
+:1004A000556E69743D00494E464F3A20736574207D
+:1004B0006E65772072656164696E673A2000676FC8
+:1004C000742076616C696420636F756E7465722048
+:1004D0006E756D6265723A20004552524F523A2055
+:1004E000696E76616C696420636F756E74657220E5
+:1004F0006E756D626572004552524F523A206D69B9
+:100500007373696E672076616C696420636F756EC2
+:10051000746572206E756D62657200534156494E66
+:100520004720434F4E46494700696E76616C6964C7
+:1005300020636F6D6D616E6400756E6B6E6F776EAC
+:1005400020706172616D657465722027004552529A
+:100550004F52202D20696E76616C69642073796E2C
+:10056000746178006D697373696E6720636F756E6F
+:10057000746572206E756D626572006465626F7578
+:100580006E63653A20002C206465626F756E63654A
+:100590005265636F763D005245533A20736574206F
+:1005A0006465626F756E63653D005245533A207312
+:1005B000657420707772476F6F643D00696E766175
+:1005C0006C696420636F756E746572206E756D6200
+:1005D0006572006D697373696E6720636F756E7401
+:1005E0006572206E756D62657200696E76616C6908
+:1005F0006420636F756E746572206E756D626572CE
+:10060000006D697373696E6720636F756E746572D0
+:10061000206E756D6265720044454255472044491D
+:100620005341424C454400444542554720454E41C4
+:10063000424C45440000000000250028002B00002B
+:10064000000000240027002A0020636F6E6669679F
+:100650002073617665496E7420697320696E7661D6
+:100660006C696420286F7574206F662072616E67F4
+:100670006520302D333630302921005741524E4904
+:100680004E473A2043002C2073617665496E743DD5
+:100690000020636F6E666967206E6F496D70546FDE
+:1006A000757420697320696E76616C696420286FA7
+:1006B0007574206F662072616E676520302D333649
+:1006C00030302921005741524E494E473A204300CD
+:1006D0002C206E6F496D70546F75743D0020636FF0
+:1006E0006E66696720696D70506572556E69742019
+:1006F000697320696E76616C696421005741524EBE
+:10070000494E473A204300696D70506572556E69D5
+:10071000743D006C6F6164696E6720636F756E7401
+:1007200065727320636F6E663A00696E76616C69FC
+:10073000642076616C75652073746F7265640070F7
+:100740007772476F6F643A2000696E76616C6964F6
+:100750002076616C75652073746F726564006465E2
+:10076000626F756E6365323A2000696E76616C69FE
+:10077000642076616C75652073746F7265640064C3
+:1007800065626F756E6365313A2000202D20696EB9
+:1007900076616C69642076616C75652073746F7224
+:1007A0006564006A736F6E3A2000202D20696E76B2
+:1007B000616C69642076616C75652073746F726515
+:1007C000640064656275676C6576656C3A20006CE0
+:1007D0006F6164696E6720676C6F62616C20636F24
+:1007E0006E663A00494E464F3A20726573746F72D6
+:1007F00065642072656164696E67206F66204300DE
+:100800004552524F523A204641494C454420746F5C
+:1008100020726573746F7265206C617374207265E9
+:100820006164696E67206F66204300494E464F3A07
+:100830002073746F7265642072656164696E67739A
+:10084000203220616E6420332061726520657175ED
+:10085000616C00494E464F3A2073746F7265642094
+:1008600072656164696E6773203120616E64203344
+:100870002061726520657175616C00494E464F3A82
+:100880002073746F7265642072656164696E67734A
+:10089000203120616E64203220617265206571759F
+:1008A000616C00747279696E6720746F2072657371
+:1008B000746F7265206C6173742072656164696E17
+:1008C0006720666F72204300207374617274696ED2
+:1008D000672E2E2E0073656E642064617461206F34
+:1008E0006E206E6F496D70546F7574204300202820
+:1008F0006E6F496D70546F75742900494E464F3ABA
+:1009000020736176656420696D70436F756E742025
+:1009100043002028666978656420696E7465727684
+:10092000616C2900494E464F3A2073617665642018
+:10093000696D70436F756E742043000000000023E2
+:100940000026002900040404040404040402020232
+:100950000202020303030303030102040810204000
+:100960008001020408102001020408102000000089
+:10097000080002010000030407000000000000005E
+:1009800000494E464F3A20736176656420616C6C75
+:100990002063757272656E7420646174612E00004C
+:1009A000DF1B11241FBECFEFD8E0DEBFCDBF24E098
+:1009B000A2E1B3E001C01D92A53DB207E1F713E04B
+:1009C000A0E0B1E0E8E3FAE302C005900D92A231A5
+:1009D000B107D9F714E0C1EDD4E004C02197FE01BE
+:1009E0000E94F21CC03DD107C9F70E941D160C944D
+:1009F0001A1D0C94000083E480937C0080917A009F
+:100A0000806480937A0080917A0086FDFCCF80918B
+:100A10007800909179000895AF92BF92CF92DF92C3
+:100A2000EF92FF920F931F93CF93DF936C017B01A3
+:100A30008B01040F151FEB015E01AE18BF08C01734
+:100A4000D10759F06991D601ED91FC910190F081A7
+:100A5000E02DC6010995892B79F7C501DF91CF916A
+:100A60001F910F91FF90EF90DF90CF90BF90AF90CC
+:100A70000895FC01538D448D252F30E0842F90E0A4
+:100A8000821B930B541710F0CF9608950197089589
+:100A9000FC01918D828D981761F0A28DAE0FBF2F52
+:100AA000B11D5D968C91928D9F5F9F73928F90E0A8
+:100AB00008958FEF9FEF0895FC01918D828D981717
+:100AC00031F0828DE80FF11D858D90E008958FEF54
+:100AD0009FEF0895FC01918D228D892F90E0805C1D
+:100AE0009F4F821B91098F739927089586E394E0A5
+:100AF0000E946A0521E0892B09F420E0822F0895E5
+:100B0000FC01A48DA80FB92FB11DA35ABF4F2C9182
+:100B1000848D90E001968F739927848FA689B78979
+:100B20002C93A089B1898C91837080648C93938D70
+:100B3000848D981306C00288F389E02D80818F7D13
+:100B400080830895EF92FF920F931F93CF93DF93CB
+:100B5000EC0181E0888F9B8D8C8D98131AC0E889F9
+:100B6000F989808185FF15C09FB7F894EE89FF89C8
+:100B70006083E889F98980818370806480839FBF66
+:100B800081E090E0DF91CF911F910F91FF90EF9066
+:100B90000895F62E0B8D10E00F5F1F4F0F73112776
+:100BA000E02E8C8D8E110CC00FB607FCFACFE889B1
+:100BB000F989808185FFF5CFCE010E948005F1CFB4
+:100BC000EB8DEC0FFD2FF11DE35AFF4FF0829FB725
+:100BD000F8940B8FEA89FB8980818062CFCF0F93D5
+:100BE0001F93CF93DF938C01D0E0C0E0F801EC0FAE
+:100BF000FD1F6491662341F086E394E00E94A20504
+:100C0000892B11F02196F2CFCE01DF91CF911F9168
+:100C10000F910895CF93DF93EC01888D8823B9F06D
+:100C2000AA89BB89E889F9898C9185FD03C08081F7
+:100C300086FD0DC00FB607FCF7CF8C9185FFF2CF74
+:100C4000808185FFEDCFCE010E948005E9CFDF9145
+:100C5000CF910895833081F028F4813099F082306B
+:100C6000A9F008958730A9F08830C9F08430B1F434
+:100C7000809180008F7D03C0809180008F7780936A
+:100C80008000089584B58F7784BD089584B58F7DE5
+:100C9000FBCF8091B0008F778093B0000895809152
+:100CA000B0008F7DF9CFCF93DF9390E0FC01E75A3E
+:100CB000F64F24918B5B964FFC0184918823C9F0F9
+:100CC00090E0880F991FFC01E15CF94FA591B49168
+:100CD000FC01EB5CF94FC591D49161110DC09FB738
+:100CE000F8948C91209582238C93888128232883E3
+:100CF0009FBFDF91CF910895623051F49FB7F89470
+:100D00003C91822F809583238C93E8812E2BEFCF0B
+:100D10008FB7F894EC912E2B2C938FBFEACF3FB76F
+:100D2000F8948091ED039091EE03A091EF03B091C0
+:100D3000F00326B5A89B05C02F3F19F00196A11D11
+:100D4000B11D3FBFBA2FA92F982F8827BC01CD0115
+:100D5000620F711D811D911D42E0660F771F881F74
+:100D6000991F4A95D1F708958F929F92AF92BF92A3
+:100D7000CF92DF92EF92FF926B017C010E948F066F
+:100D80004B015C01C114D104E104F104B9F00E94EB
+:100D90008F06681979098A099B09683E73408105A5
+:100DA000910580F321E0C21AD108E108F10888EE2C
+:100DB000880E83E0981EA11CB11CE4CFFF90EF9039
+:100DC000DF90CF90BF90AF909F908F9008952FB7F6
+:100DD000F8946091E9037091EA038091EB0390919C
+:100DE000EC032FBF0895FC0101900020E9F7319733
+:100DF000AF01481B590BBC0186E394E00C940C0531
+:100E00008AE491E00C94F306CF93DF930E94EF0500
+:100E1000EC010E9400078C0F9D1FDF91CF91089578
+:100E20008F929F92AF92BF920F931F93CF93DF93B6
+:100E3000CDB7DEB7A1970FB6F894DEBF0FBECDBF1A
+:100E400019A2423008F44AE08E010F5D1F4F842E34
+:100E5000912CB12CA12CA50194010E94D01CE62F4D
+:100E6000B901CA01EA30F4F4E05DD801EE938D01D6
+:100E7000232B242B252B79F790E080E0109719F095
+:100E8000CD010E94F306A1960FB6F894DEBF0FBE07
+:100E9000CDBFDF91CF911F910F91BF90AF909F90E9
+:100EA0008F900895E95CE1CF009711F00C94F30660
+:100EB00090E080E00895CF93DF930E94F306EC0169
+:100EC0000E9400078C0F9D1FDF91CF910895BC01F8
+:100ED00090E080E04AE00C941007CF93DF930E94EB
+:100EE0006707EC010E9400078C0F9D1FDF91CF91D7
+:100EF0000895CF92DF92EF92FF92CF93DF936C0130
+:100F0000990FEE08FF08F7FE19C06DE286E394E042
+:100F10000E94A205EC0166277727CB016C197D0999
+:100F20008E099F094AE00E9410078C0F9D1FDF91D8
+:100F3000CF91FF90EF90DF90CF9008954AE0C701E6
+:100F4000B601DF91CF91FF90EF90DF90CF900C949E
+:100F50001007CF93DF930E947907EC010E940007EE
+:100F60008C0F9D1FDF91CF910895CF93DF93C82FF2
+:100F70008DED90E00E94EF05D0E0CE0101960E9439
+:100F800079078FEC90E00E94EF05CC0FDD1FFE018A
+:100F9000E05FFE4F808191810E94670782EC90E0C4
+:100FA0000E94EF05FE01E85FFE4F808191810E9463
+:100FB000670787EB90E00E94EF05C45FDE4F8881F2
+:100FC00099810E946707DF91CF910C940007682FE9
+:100FD00070E090E080E04AE00C941007CF93DF933C
+:100FE0000E94E707EC010E9400078C0F9D1FDF9114
+:100FF000CF910895CF93DF934AE00E941007EC0150
+:101000000E9400078C0F9D1FDF91CF9108958F9252
+:101010009F92AF92BF92DF92EF92FF920F931F9336
+:10102000CF93DF934A015B01D22EC82FD0E07E011F
+:101030002FEFE21AF20A809100018E01000F111FBA
+:10104000000F111FCC0FDD1F882309F47BC08DE832
+:1010500090E00E94EF05C7010E94790780E890E0C8
+:101060000E94EF05F801EF5EFB4F60817181828184
+:1010700093814AE00E94100780E193E00E945407A8
+:10108000FE01E05FFE4F808191818436910509F079
+:1010900046C0FE01E75EFB4F808191810A9720F4F4
+:1010A0008BEB91E00E945407FE01E75EFB4F8081CD
+:1010B00091810E94670783E790E00E94EF05C05F7F
+:1010C000DE4F888199810E946707DD2049F088E61C
+:1010D00090E00E94EF054AE0C501B4010E941007AC
+:1010E00080E591E00E945B07F801E750FC4F80919A
+:1010F0000D0490910E04A0910F04B0911004808310
+:101100009183A283B383DF91CF911F910F91FF90C1
+:10111000EF90DF90BF90AF909F908F900895883EA2
+:10112000934011F6FE01E75EFB4F808191818A308A
+:10113000910518F48DE491E0B5CF8436910508F05F
+:10114000B3CFAECF82E591E00E945407C7010E9461
+:1011500079078DE592E00E945407F801EF5EFB4F9E
+:1011600060817181828193814AE00E94100780E151
+:1011700093E00E945407FE01E05FFE4F8081918161
+:101180008436910551F5FE01E75EFB4F8081918128
+:101190000A9720F48BEB91E00E945407FE01E75E72
+:1011A000FB4F808191810E94670784E591E00E9456
+:1011B0005407C05FDE4F888199810E946707DD2058
+:1011C00049F084E591E00E9454074AE0C501B4016A
+:1011D0000E9410070E94000787CF883E9340F1F6D7
+:1011E000FE01E75EFB4F808191818A30910518F402
+:1011F0008DE491E0D1CF8436910580F6CBCF20E00D
+:1012000040E050E0BA0180E00E94070820E040E0A2
+:1012100050E0BA0181E00C940708CF92DF92EF9280
+:10122000FF920F931F93CF93DF93EB017B0124E099
+:10123000E20EF11C8B016C01C61AD70AC601800FA1
+:10124000911F0E94A41CF80181938F01EE15FF05E8
+:10125000A9F7CE01DF91CF911F910F91FF90EF90F1
+:10126000DF90CF9008950F931F93CF93DF938C015E
+:10127000EB010E94A41C8883C80101960E94A41C53
+:101280008983CE01DF91CF911F910F9108952F9205
+:101290003F924F925F926F927F928F929F92AF9206
+:1012A000BF92CF92DF92EF92FF920F931F93CF9353
+:1012B000DF93CDB7DEB72E970FB6F894DEBF0FBE23
+:1012C000CDBF362E1A8219821C821B829091070193
+:1012D000482E512C911102C0662381F00E94000714
+:1012E0000E9400078FEE91E00E94EF05C201019677
+:1012F0000E9479078EE093E00E945B078201000F55
+:10130000111FF801E25EFE4F808191819C878B87DF
+:1013100096958795969587959A87898780910701F5
+:10132000811102C0332061F086E591E00E945407EC
+:1013300089859A850E946D078CEC91E00E940407D4
+:10134000D12CC12C1E82B12CA12C712C612C212CF2
+:101350001D8218861F82F801E65EFE4FFE87ED872C
+:1013600089859A85C816D90608F0A7C04601880C59
+:10137000991C880C991CED85FE85E080F180E80CB5
+:10138000F91C80910701811102C03320B1F0C40122
+:10139000969587959695879501960E94670781E6B1
+:1013A00091E00E945407C4010E94670781E691E022
+:1013B0000E945407C7010E946707C114D10421F09D
+:1013C00089819A8198878F83BE016F5F7F4FC701A4
+:1013D0000E943309BE016D5F7F4FC70102960E94D4
+:1013E000330980910701811102C03320C1F081E6E9
+:1013F00091E00E94540789819A810E94670783E6E1
+:1014000091E00E9454078F8198850E94670783E6C8
+:1014100091E00E9454078B819C810E946707E980BC
+:10142000FA8080910701C114D104E9F4E114F104B8
+:10143000D1F06B807C80811102C03320D9F185E628
+:1014400091E00E94540791E09E83809107018111F1
+:1014500001C031100E9400079FEFC91AD90A540138
+:101460002E2CFD827DCF2F8138852F5F3F4F2E158B
+:101470003F0579F4811102C0332021F085E691E027
+:101480000E945407E980FA806B807C80E1E0EE8363
+:10149000DCCFC984DA84FFEFCF1ADF0A811102C0E2
+:1014A000332021F088E691E00E9454074501E22CA8
+:1014B000FD80CBCF81E08E83C8CFEE81E11136C0B5
+:1014C00080910701811127C0311025C0F801EF502C
+:1014D000FC4F11821082F801EB50FC4F81E090E04C
+:1014E000918380832E960FB6F894DEBF0FBECDBFDA
+:1014F000DF91CF911F910F91FF90EF90DF90CF90F0
+:10150000BF90AF909F908F907F906F905F904F9023
+:101510003F902F9008958EE991E00E94EF05C2015F
+:1015200001960E94A9073110DDCFD0CF7501F4E0FC
+:10153000EF0EF11C8B859C8504978E159F0510F48A
+:10154000F12CE12C8FE491E0311017C0F801EF503D
+:10155000FC4FF182E082F801EB50FC4F20828D813C
+:101560008183F801E75EFB4F71826082F801E75FDB
+:10157000FB4F718260828AE791E00E94EF05C20111
+:1015800001960E94790787E491E00E94EF05C3016C
+:101590000E94670780910701811102C0332019F171
+:1015A0008DE391E00E94EF05822D9D810E946707E7
+:1015B00085E391E00E94EF05C50196958795969584
+:1015C000879501960E9467078BE291E00E94EF05E4
+:1015D000C5010E94670780E291E00E94EF05C70104
+:1015E0000E946D077FCF0E9400077CCFCF93DF93CF
+:1015F000EB010E94A41C8883CE01DF91CF91089556
+:10160000FF920F931F93CF93DF93EC01F62E088187
+:101610001981C8010E94A41CF81621F06F2DC80181
+:101620000E94B21CCE01DF91CF911F910F91FF90CC
+:1016300008950F931F93CF93DF9300D0CDB7DEB7FC
+:101640008B019A838983FB016081CE0101960E9400
+:10165000000BC8010F900F90DF91CF911F910F9158
+:101660000895AF92BF92CF92DF92EF92FF920F93C5
+:101670001F93CF93DF9300D0CDB7DEB78B016B0103
+:1016800024E0C20ED11C7B015C01A61AB70AC50179
+:101690008E0D9F1D9A838983F70161917F01CE0191
+:1016A00001960E94000BEC14FD0489F7C8010F900D
+:1016B0000F90DF91CF911F910F91FF90EF90DF90EE
+:1016C000CF90BF90AF900895FF920F931F93CF9349
+:1016D000DF93823008F048C0F62EC82FD0E08E018C
+:1016E000000F111FC8018D5F9E4F0E94AC1C092E78
+:1016F000000CAA0BBB0BFE01EE0FFF1FEE0FFF1F2E
+:10170000EF5EFB4F408151816281738184179507A1
+:10171000A607B70711F4FF2039F1CC0FDD1FCC0F5E
+:10172000DD1FCF5EDB4FF801ED5FFE4FBE01808114
+:1017300091810E94310BF801EC5BFE4FBE0180816C
+:1017400091810E94310BF801E05CFE4FBE01808167
+:1017500091810E94310B89EF90E0DF91CF911F9131
+:101760000F91FF900C940407DF91CF911F910F917F
+:10177000FF900895EF92FF920F931F93CF93DF9303
+:1017800000D0CDB7DEB78C017B019A838983FB0142
+:101790006081CE0101960E94000B0F5F1F4F1A83DC
+:1017A0000983F7016181CE0101960E94000BC701F8
+:1017B0000F900F90DF91CF911F910F91FF90EF90BD
+:1017C0000895CF92DF92EF92FF920F931F93CF93E2
+:1017D000DF93082F10E0E801CC0FDD1F61110EC070
+:1017E000FE01E75FFB4F20813181FE01E75EFB4F89
+:1017F000808191812817390709F49BC0FE01EB50C5
+:10180000FC4F808191818F3F980709F09BC081E058
+:1018100090E091838083FE01EF50FC4F1182108293
+:10182000CE018F509C4F6C01FE01E65EFE4FE080C2
+:10183000F180FC0180819181E80EF91E8091070101
+:101840008823A9F18AE692E00E94EF05C80101967B
+:101850000E94790782E692E00E94EF05FE01E75EB2
+:10186000FB4F808191810E94670788E592E00E948A
+:10187000EF05FE01EB50FC4F808191810E946707CC
+:101880008EE492E00E94EF05F601808191810E9432
+:10189000670786E492E00E94EF05F601808191815E
+:1018A000969587959695879501960E946D07680194
+:1018B000CC0CDD1CB601675E7B4FC70102960E940F
+:1018C000BA0BB6016B507C4FC7010E94BA0B8BE17B
+:1018D00092E00E940407FE01E75FFB4FDE01A75E76
+:1018E000BB4F8D919C9191838083000F111F000F3E
+:1018F000111FF801EF5FFB4F80910D0490910E04D2
+:10190000A0910F04B091100480839183A283B383CC
+:10191000FE01EF50FC4F808191810496C25EDE4F44
+:1019200028813981245031092817390778F4118228
+:101930001082DF91CF911F910F91FF90EF90DF9078
+:10194000CF9008950196918380836ACF918380839D
+:10195000F0CF60E080E00E94E10B60E080E00E9458
+:10196000640B60E081E00E94E10B60E081E00E9496
+:10197000640B81E899E00C940407CF93DF93EC01AA
+:101980000E94A90C82E892E00E94EF05CE010E941D
+:1019900079078BE691E00E945B0786E394E00E9462
+:1019A0000A06E0914804F091490480818F7E80838B
+:1019B000E0914804F09149048081877F8083E09121
+:1019C0004804F091490480818F778083E091480436
+:1019D000F091490480818F7D8083809150048093B1
+:1019E0004F04BE01DD0F880B990B0E94B40661E025
+:1019F00086E00E945306E3E7F9E08491EFE5F9E021
+:101A0000D491EBE4F9E0C491CC2399F081110E94C8
+:101A10002A06EC2FF0E0EE0FFF1FEB5CF94FA591CB
+:101A2000B4918FB7F8949C91ED2FE095E923EC9356
+:101A30008FBFDF91CF91089584EE90E00E9404075C
+:101A40008091160190911701893C910530F466E16F
+:101A500071E084E090E00E94BA0B809114019091B3
+:101A60001501853F914030F464E171E086E090E03B
+:101A70000E94BA0B80911801909119018115944030
+:101A800030F468E171E088E090E00C94BA0B0895BE
+:101A9000EF92FF920F931F93CF93DF9300D0CDB7B8
+:101AA000DEB78C017C01E60EF71E81E0E81AF10832
+:101AB00088E990E00E94EF05C8010E94790783E958
+:101AC00090E00E94EF05C7010E94A907E016F10609
+:101AD00074F080E193E00E9454071A83098360E068
+:101AE000CE0101960E94000B0F5F1F4FEFCF81E7E1
+:101AF00091E00E945B070F900F90DF91CF911F91B3
+:101B00000F91FF90EF900895CF93DF938230B0F55F
+:101B1000C82FD0E0CC0FDD1FFE01ED5FFE4F64E06B
+:101B200070E0808191810E94480DFE01EC5BFE4FC8
+:101B300064E070E0808191810E94480DFE01E05CCC
+:101B4000FE4F64E070E0808191810E94480DFE01AB
+:101B5000E25EFE4F60817181FE01E65EFE4F808194
+:101B600091810E94480DFE01EF50FC4F11821082BE
+:101B7000CB50DC4F81E090E099838883DF91CF9157
+:101B800008952F923F924F925F926F927F928F9221
+:101B90009F92AF92BF92CF92DF92EF92FF920F93FC
+:101BA0001F93CF93DF93CDB7DEB766970FB6F89448
+:101BB000DEBF0FBECDBF16EE212E13E0312E86E321
+:101BC00094E00E946A05892B09F476C786E394E0C5
+:101BD0000E9448052091E6033091E703F901E3599B
+:101BE000FC4F80838D3019F08A3009F03DC7108298
+:101BF000121613060CF02CC780910701882361F0A0
+:101C000086E791E00E9454078DE693E00E94540716
+:101C10008BE791E00E945B0742E050E06DE771E0E6
+:101C20008DE693E00E940C1D892BB9F4EDE6F3E0FC
+:101C300001900020E9F7E057F34079F480E891E063
+:101C40000E94540781E991E00E94540784E991E0E1
+:101C50000E9454070E94000742C04AE050E068E931
+:101C600071E08DE693E00E940C1D892B09F046C0BF
+:101C7000EDE6F3E001900020E9F7E857F340F1F5D5
+:101C800085EB92E00E94040780EA92E00E9404073C
+:101C900010E000E0F12CE12CC7010E94A41CD82E1A
+:101CA0000115110539F4C7010E94790783E691E017
+:101CB0000E9454078D2D0E94E70783E691E00E9461
+:101CC00054075FEFE51AF50A07301105A4F00E94EA
+:101CD000000710E000E0E11444E0F406E9F6109299
+:101CE000E7031092E603EDE6F3E02E163F0609F453
+:101CF00066CF1192FACF0F5F1F4FEDCF49E050E052
+:101D000063EA71E08DE693E00E940C1D892B59F483
+:101D1000EDE6F3E001900020E9F7E757F34019F40E
+:101D20000E94A90CDCCF47E050E06DEA71E08DE63F
+:101D300093E00E940C1D892BF1F4EDE6F3E0019095
+:101D40000020E9F7E557F340B1F481E08093070103
+:101D500021E030E03093020120930101898387E282
+:101D600096E00E940407BE016F5F7F4F82E090E023
+:101D70000E94190BB4CF47E050E065EB71E08DE6AF
+:101D800093E00E940C1D892B91F4EDE6F3E00190A5
+:101D90000020E9F7E557F34051F410920701109243
+:101DA000020110920101198288E196E0DACF4AE03F
+:101DB00050E06DEB71E08DE693E00E940C1D892BE5
+:101DC000E9F5EDE6F3E001900020E9F7E857F3408C
+:101DD000A9F560E072E080E890E00E94480D64E0C0
+:101DE00070E080910301909104010E94480D64E02D
+:101DF00070E084E290E00E94480D64E070E088E2C8
+:101E000090E00E94480D60E870E080E892E00E9457
+:101E1000480D64E070E080910501909106010E94F8
+:101E2000480D64E070E080E390E00E94480D64E0BB
+:101E300070E084E390E00E94480D51CF48E050E00C
+:101E400068EC71E08DE693E00E940C1D892B41F552
+:101E50008DE693E0DC010D900020E9F7CD018E5670
+:101E6000934088309105E0F08830910529F481E0B5
+:101E700096E00E94040733CF099709F030CF809194
+:101E8000750389831A82CE0101960E940C1C815031
+:101E9000823018F40E94840D22CF8AEE95E0E9CFBB
+:101EA0004CE050E061ED71E08DE693E00E940C1D86
+:101EB000892B59F4EDE6F3E001900020E9F7EA57A9
+:101EC000F34019F40E94FF080ACF49E050E06EED9C
+:101ED00071E08DE693E00E940C1D892B39F58DE6AB
+:101EE00093E0FC0101900020E9F7CF018E5693406A
+:101EF00089309105D8F08930910519F483ED95E08A
+:101F0000B8CF0A9709F0EBCE8091760389831A82C5
+:101F1000CE0101960E940C1C8150823020F461E0B9
+:101F20000E944709DCCE8CEB95E0A3CF4BE050E05C
+:101F300068EE71E08DE693E00E940C1D892BD9F4C8
+:101F4000EDE6F3E001900020E9F7E957F34099F45A
+:101F50008DEC92E00E94EF050E94FB040E9479073D
+:101F600082EC92E00E94EF05809118019091190196
+:101F70000E9467076FCE4BE050E064EF71E08DE6A2
+:101F800093E00E940C1D892B09F064C08DE693E05C
+:101F9000DC010D900020E9F7CD018E5693408D3085
+:101FA000910508F457C0E3EFE80F90E080E08E174A
+:101FB00074F48A35910548F4DC01A359BC4F1D9691
+:101FC0002C91DC01AE5EBC4F2C930196F0CF0E2E0F
+:101FD000000CFF0BEE5EFC4F10822DE0EDE6F3E00F
+:101FE000DF010D900020E9F7BD016E56734083EFCD
+:101FF000820F90E0422F50E04617570770F461E0DF
+:1020000070E06C0F7D1F860F971F43595C4FDA01FC
+:102010003C91DC013C932F5FE3CFE1E0F0E0EC0F7B
+:10202000FD1F8E0F9F1FDC011C92CF010E940C1C14
+:102030008C018AEA95E00E94EF05802F0E94E70755
+:102040000E940007112710931901009318010E94A4
+:102050001C0D45CE4AE050E060E072E08DE693E072
+:102060000E940C1D892B89F4EDE6F3E0019000201D
+:10207000E9F7E857F34049F4109200011982BE01D4
+:102080006F5F7F4F83E090E073CE4AE050E06BE0FB
+:1020900072E08DE693E00E940C1D892B69F4EDE659
+:1020A000F3E001900020E9F7E857F34029F481E0DC
+:1020B000809300018983E3CF48E050E066E172E05D
+:1020C0008DE693E00E940C1D892BE1F58DE693E0EF
+:1020D000DC010D900020E9F7CD018E569340089762
+:1020E00088F180E093E00E94EF05809101019091DA
+:1020F00002010E94790784EF92E00E94EF0580912F
+:102100001601909117010E94790788EE92E00E94D3
+:10211000EF0580911401909115010E9479078DEDD2
+:1021200092E00E94EF0580911801909119010E94A0
+:1021300067070E94000780E00E94B50781E00E94C7
+:10214000B507CDCD4CE050E06FE172E08DE693E055
+:102150000E940C1D892B09F0B3C08DE693E0FC01B1
+:1021600001900020E9F7CF018E5693408E30910503
+:1021700008F4A6C0E3EFE80F90E080E08E1774F457
+:102180008A35910548F4DC01A359BC4F1D962C916A
+:10219000DC01AE5EBC4F2C930196F0CF0E2E000CEE
+:1021A000FF0BEE5EFC4F10829DE060E080E0ADE64C
+:1021B000B3E0FD0101900020E9F7EE56F340262F31
+:1021C00030E0492F50E04E175F07A8F443595C4FA9
+:1021D000FA0140814C3269F0811109C0EBE0F0E076
+:1021E000EC0FFD1F2E0F3F1FF90140836F5F9F5FB4
+:1021F000E0CF892FFCCF4BE050E04C0F5D1F240F48
+:10220000351FD9011C92882309F457C031E0380FDB
+:10221000EDE6F3E0282F2095DF010D900020E9F78F
+:10222000BD016E567340822F830F90E0432F50E024
+:102230004617570770F461E070E06C0F7D1F860F42
+:10224000971F43595C4FDA014C91DC014C933F5F7F
+:10225000E3CFE1E0F0E0EC0FFD1F8E0F9F1FDC01EC
+:102260001C92DD24D394CE010B960E940C1C8C0191
+:10227000CE0101960E940C1C7C01B8ECB01760F0F6
+:1022800087E995E00E94EF05802F0E94E70711275C
+:102290001093170100931601DD2061F086E895E0A8
+:1022A0000E94EF058E2D0E94E707FF24F092150192
+:1022B000E09214010E940007CACE1982D12CD3CF1C
+:1022C0004CE050E06CE272E08DE693E00E940C1D61
+:1022D000892BE9F4EDE6F3E001900020E9F7EA57F5
+:1022E000F340A9F48BE795E00E94EF058091160179
+:1022F000909117010E94790789E392E00E945407A8
+:1023000080911401909115010E94A907E8CC4AE040
+:1023100050E06CE372E08DE693E00E940C1D892B87
+:1023200009F0F4C08DE693E0DC010D900020E9F7A0
+:10233000CD018E5693408A30910508F4E7C08A306B
+:10234000910519F484E695E094CD8F30910508F459
+:10235000C6CC8A5040E0082E000C990B242F30E0A8
+:10236000281739076CF44A3548F4F901EE5EFC4F42
+:1023700023593C4FD9011A962C9120834F5FEECF01
+:102380008E5E9C4FFC01108287E492E00E9454070D
+:1023900082E193E00E9454078BE791E00E945B0783
+:1023A0008091120389831A82CE0101960E940C1C2F
+:1023B000082F77247A94780EF1E0F71508F451C0CD
+:1023C00088E592E00E945407802F0E94EE0782E188
+:1023D00093E0DC010D900020E9F7CD01835193409B
+:1023E000059708F446C06AE372E082E193E00E9438
+:1023F000511C6C010150110B000F111FF801E45F1B
+:10240000FE4F4F019801285F3E4F5901005F1E4F5C
+:10241000C114D10409F463CC6DE370E0C6010E94DD
+:10242000F81C009709F449C0DC011D927D01C6012A
+:102430000E94561C6FE672E0C6010E94031D892BA4
+:1024400019F58AE792E00E945407C7010E940C1C0C
+:102450000E94A907C7010E940C1CF8019183808388
+:1024600029C080911303803239F08DE495E00E94F9
+:10247000040789E295E0FDCC8FE592E00E945407C5
+:10248000802F0E94EE07F5CF66E872E0C6010E9439
+:10249000031D892BD1F480E992E00E945407C70103
+:1024A0000E940C1C0E94A907C7010E940C1CD501A8
+:1024B0008D939C93872D0E94B50764E571E090E0B1
+:1024C00080E00E94511C6C01A3CF6BE972E0C60151
+:1024D0000E94031D892B71F483EA92E00E94540745
+:1024E000C7010E940C1C0E94A907C7010E940C1C76
+:1024F000F401B4CF89E395E00E94EF05C6010E9484
+:1025000054078BE791E00E945B07D4CF49E050E08D
+:102510006CEA72E08DE693E00E940C1D892B09F0B5
+:10252000C0C0EDE6F3E001900020E9F7E757F34083
+:1025300009F0B7C08BE195E00E94040750E1A52E99
+:1025400051E0B52E64E3862E61E0962E7CE0C72E26
+:1025500071E0D72EE8E36E2EE1E07E2EF8E0EF2E5C
+:10256000F1E0FF2EACE34A2EA1E05A2E01E010E08C
+:1025700087EF93E00E94EF05C8010E94790788EE7B
+:1025800093E00E94EF05D5018D919C910E946D070B
+:10259000F501808191818A30910539F08436910569
+:1025A00021F0883E934009F058C0B501D2018D91C9
+:1025B0009C910E94BA0B88EA93E00E94EF05C80143
+:1025C0000E9479078AE993E00E94EF05F701808174
+:1025D00091810E946D07D7018D919C9181319E4020
+:1025E00008F047C0B701F301808191810E94BA0BC6
+:1025F0008BE593E00E94EF05C8010E9479078DE406
+:1026000093E00E94EF05D6018D919C910E946D0789
+:10261000F6018081918181319E40B8F5B601D401E7
+:102620008D919C910E94BA0BB2E0AB0EB11CE2E01E
+:102630008E0E911CF2E0CF0ED11C22E0620E711CB6
+:1026400032E0E30EF11C42E0440E511C0230110551
+:1026500009F4FDCC02E010E08BCF8DED93E00E94F9
+:10266000EF05C8010E94790781EB93E00E940407FF
+:10267000A2CF8FE893E00E94EF05C8010E9479077E
+:1026800084E693E00E940407B3CF82E493E00E94C3
+:10269000EF05C8010E94790787E193E00E940407D3
+:1026A000C3CF4BE050E066EB72E08DE693E00E9412
+:1026B0000C1D892B09F043C14DE6E42E43E0F42EB6
+:1026C000D7010D900020E9F7CD018E5693408B3055
+:1026D000910508F434C10E9718F487EF94E0C9CB44
+:1026E00080917803803209F0FACA809179038336A9
+:1026F00009F0F5CA80917A038D8B1E8ACE0145962A
+:102700000E940C1C082F1FEF180F89ED94E0123067
+:1027100008F0AFCB8EEB94E00E94EF05802F0E9473
+:10272000EE0782EC92E00E945B07F7010190002027
+:10273000E9F7CF018E569340409708F4D0CA00E0E5
+:10274000802F90E0FC01E359FC4F2785422F022E99
+:10275000000C550B405351094A30510560F40930C3
+:1027600040F44BE050E04C0F5D1F840F951FDC01DF
+:102770002C930F5FE5CF322F3D7F3C3209F440C0F0
+:10278000203209F040C0912C0F5FF12CEBE0F0E01B
+:10279000EC0FFD1F8E0F9F1FDC011C92CF010E94CA
+:1027A0002A1C2B013C01E0E0FF20B1F1911097CAF7
+:1027B00081E394E00E94EF05C301B2010E94FA0791
+:1027C000812F90E0FC01EE0FFF1FEE0FFF1FEF5E69
+:1027D000FB4F4082518262827382880F991FFC01F5
+:1027E000E75EFB4F11821082812F0E94840D61E011
+:1027F000812F0E94640B61E0812F0E94E10B6FCA60
+:1028000099249394C1CF21119BCF912CFF24F39451
+:10281000BDCF8F7D09F42FC1A02FB0E0A359BC4FCD
+:102820001F968C91282F082E000C330B2053310952
+:102830002A30310570F7E93038F4A1E0B0E0AC0F90
+:10284000BD1FAE0FB11D8C930F5FEF5FE5CFF5019C
+:10285000E05FFE4F808191818A309105A1F4BAE05A
+:10286000CB16D104B8F08AE794E00E94EF05F50199
+:10287000E05FFE4F808191810E9467078EEC92E0BD
+:102880000E945B072CCA84369105A9F5E4E6CE16B2
+:10289000D10448F786EA94E00E94EF054AE0C301BC
+:1028A000B2010E94100780E193E00E945407F501F5
+:1028B000E05FFE4F808191818436910589F55AE071
+:1028C000C516D10420F48BEB91E00E945407C60199
+:1028D0000E946D07F701EE0FFF1FEE0FFF1FEF5E67
+:1028E000FB4F4082518262827382F501E75EFB4FAB
+:1028F000D182C08279CF883EF3E09F0731F428EE81
+:10290000C21623E0D20630F2AECF8031974209F0F2
+:10291000AACF40E1C41647E2D40608F0A4CFBACF4C
+:10292000883E9340A1F67AE0C716D10418F48DE4EE
+:1029300091E0CBCF84E6C816D10448F6C4CF4AE074
+:1029400050E063ED72E08DE693E00E940C1D892B50
+:1029500069F5EDE6F3E001900020E9F7E857F34070
+:1029600029F588E294E00E94EF0581E090E00E9462
+:1029700079078DE592E00E9454078091F5039091CC
+:10298000F6030E946D0788E294E00E94EF0582E062
+:1029900090E00E9479078DE592E00E9454078091B3
+:1029A000F7039091F8030E946D0799C945E050E044
+:1029B0006EED72E08DE693E00E940C1D892BE9F527
+:1029C0008DE693E0DC010D900020E9F7CD018E56F5
+:1029D00093408530910588F18530910529F490E088
+:1029E00080E00E94BD0C7BC9EAEFE80F90E080E038
+:1029F0008E1774F48A35910548F4DC01A359BC4F55
+:102A000016962C91DC01AE5EBC4F2C930196F0CF54
+:102A10000E2E000CFF0BEE5EFC4F108282E193E065
+:102A20000E945B0782E193E00E940C1C8939BAE3A3
+:102A30009B07B8F283E194E01CCA80E094E00E9416
+:102A4000EF058DE693E00E9454078BE791E018CFE5
+:102A50001092E7031092E603EDE6F3E02E163F0630
+:102A600009F4ADC81192FACF2F5F3F4F3093E703BF
+:102A70002093E603A4C821E030E02C0F3D1F2E0F69
+:102A8000311DF9011082CE0101960E940C1C6C01CF
+:102A9000E12EF12C5701AA0CBB1C9110D8CE82E676
+:102AA00094E00E94EF05C301B2010E94FA0789E495
+:102AB00094E00E94EF050BCF66960FB6F894DEBF48
+:102AC0000FBECDBFDF91CF911F910F91FF90EF907F
+:102AD000DF90CF90BF90AF909F908F907F906F903E
+:102AE0005F904F903F902F9008950E94760581113E
+:102AF0000C94C10D08951F920F920FB60F921124DE
+:102B00002F933F934F935F936F937F938F939F93F5
+:102B1000AF93BF93EF93FF9386E394E00E94800509
+:102B2000FF91EF91BF91AF919F918F917F916F91A5
+:102B30005F914F913F912F910F900FBE0F901F907B
+:102B400018951F920F920FB60F9211242F938F9307
+:102B50009F93EF93FF93E0914604F09147048081A7
+:102B6000E0914C04F0914D0482FD1BC09081809156
+:102B70004F048F5F8F7320915004821741F0E091D2
+:102B80004F04F0E0EA5CFB4F958F80934F04FF9178
+:102B9000EF919F918F912F910F900FBE0F901F90EB
+:102BA00018958081F4CF1F920F920FB60F921124C7
+:102BB0002F933F938F939F93AF93BF938091E9039C
+:102BC0009091EA03A091EB03B091EC033091E803FC
+:102BD00023E0230F2D3758F50196A11DB11D209339
+:102BE000E8038093E9039093EA03A093EB03B09387
+:102BF000EC038091ED039091EE03A091EF03B0916F
+:102C0000F0030196A11DB11D8093ED039093EE0397
+:102C1000A093EF03B093F003BF91AF919F918F9179
+:102C20003F912F910F900FBE0F901F90189526E89F
+:102C3000230F0296A11DB11DD2CFCF93DF93CDB745
+:102C4000DEB764970FB6F894DEBF0FBECDBF7894A1
+:102C500084B5826084BD84B5816084BD85B58260A1
+:102C600085BD85B5816085BD80916E008160809352
+:102C70006E001092810080918100826080938100BB
+:102C800080918100816080938100809180008160CB
+:102C9000809380008091B10084608093B100809126
+:102CA000B00081608093B00080917A00846080934E
+:102CB0007A0080917A00826080937A0080917A0015
+:102CC000816080937A0080917A00806880937A0096
+:102CD0001092C1000FB6F894A895809160008861A9
+:102CE00080936000109260000FBE1092F603109265
+:102CF000F5031092F2031092F10310921104109256
+:102D00001204109213041092140410921D041092D5
+:102D10001E0410921F041092200410922504109299
+:102D2000F8031092F7031092F4031092F303109239
+:102D300015041092160410921704109218041092A1
+:102D40002104109222041092230410922404109261
+:102D5000260460E086E00E94530662E082E00E9462
+:102D6000530662E083E00E94530660ED77E080E066
+:102D700090E00E94B40688E199E20FB6F894A89515
+:102D8000809360000FBE90936000E0914604F09144
+:102D9000470482E08083E0914604F091470410826A
+:102DA000E0914204F09143041082E0914404F091D8
+:102DB000450480E1808310924E04E0914A04F09132
+:102DC0004B0486E08083E0914804F09149048081BF
+:102DD00080618083E0914804F0914904808188609B
+:102DE0008083E0914804F091490480818068808369
+:102DF000E0914804F091490480818F7D808380E8D0
+:102E000091E00E94540781E991E00E94540784E90F
+:102E100091E00E94540788EC98E00E94EF050E9420
+:102E200000071A8219828FEC97E00E940407BE0106
+:102E30006B5F7F4F82E090E00E94F60A82EC97E0A1
+:102E40000E94EF058D81823008F078C190E0909368
+:102E50000201809301010E94790780910101909104
+:102E60000201009709F063C1109207010E94000758
+:102E7000BE016B5F7F4F83E090E00E94F60A83EA19
+:102E800097E00E94EF058D81823008F063C10E94B7
+:102E9000EE078D81813009F058C180930001BE0199
+:102EA0006F5F7F4F84E090E00E9433098FE797E0E7
+:102EB0000E94EF0589819A81893C910508F051C1F2
+:102EC00090931701809316010E94A907BE016F5FBE
+:102ED0007F4F86E090E00E9433098EE597E00E94E4
+:102EE000EF0589819A81853F21E0920708F03EC174
+:102EF00090931501809314010E94A907BE016F5F92
+:102F00007F4F88E090E00E9433098FE397E00E94B2
+:102F1000EF0589819A81811534E0930708F02BC170
+:102F200090931901809318010E946D070E94000779
+:102F300083E197E00E9404077CE3C72E71E0D72E5F
+:102F4000E4E3AE2EE1E0BE2EF8E38F2EF1E09F2EFB
+:102F5000A0E1EA2EA1E0FA2E01E010E00E940007B5
+:102F600082E591E00E945407C8010E9479078CE62F
+:102F700092E00E945407BE016F5F7F4FD6018D9192
+:102F80009D916D010E94330987E097E00E94EF0553
+:102F900089819A810E94670789819A818A30910587
+:102FA00041F08436910529F0883EB3E09B0709F093
+:102FB000EAC0F70191838083BE016F5F7F4FD40128
+:102FC0008D919D914D010E94330980ED96E00E9404
+:102FD000EF0589819A810E94670789819A818131F1
+:102FE000BEE09B0708F0E8C0F801EE0FFF1FEA5FA4
+:102FF000FE4F91838083BE016F5F7F4FF50181910A
+:1030000091915F010E94330986E896E00E94EF05E6
+:1030100089819A810E94670789819A818131FEE0C6
+:103020009F0708F0E2C0F801EE0FFF1FE65FFE4FBA
+:103030009183808322E0E20EF11C0230110509F039
+:103040009FC00E94000793E0C92E91E0D92E24E48E
+:10305000A22E21E0B22E30E4832E31E0932E01E146
+:1030600014E0EE24E394F12C60E08FEF8E0D0E94CB
+:103070004709BE01675F7F4FD6018D919D916D011C
+:103080000E940D09BE016B5F7F4FF5018191919107
+:103090005F010E940D09BE016F5F7F4FD4018D91CA
+:1030A0009D914D010E940D0980910701882379F0BF
+:1030B0000E9400070E94000783EA98E00E94EF0543
+:1030C000C7010E9479078EE093E00E945B07898523
+:1030D0009A85AB85BC854D815E816F8178854980FD
+:1030E0005A806B807C8084179507A607B70709F084
+:1030F000A3C0F80180839183A283B38384159505CF
+:10310000A605B70509F08EC084EE97E00E94EF0592
+:10311000C7010E9479078DE592E00E945407F801EB
+:1031200060817181828193810E94FA07B1C0019709
+:1031300009F09CCE81E08093070198CE0E94E707BA
+:103140008AEA97E00E94040791CE8111A8CE1092DE
+:103150000001A5CE0E94E7078BE897E00E940407D4
+:103160009ECE8AE697E00E940407B0CE89E497E0FD
+:103170000E940407C3CE8AE297E00E940407D6CEDD
+:1031800002E010E0EBCE0E9400078CEF96E00E9478
+:10319000EF05C8010E9479078DED96E00E940407B3
+:1031A00082E591E00E945407C8010E9479078CE6ED
+:1031B00092E00E94540700CF0E94000785EC96E041
+:1031C0000E94EF05C8010E94790781E996E00E94FC
+:1031D000040782E591E00E945407C8010E94790724
+:1031E0008CE692E00E94540706CF0E9400078BE70E
+:1031F00096E00E94EF05C8010E94790789E496E0F5
+:103200000E94040782E591E00E945407C8010E94D1
+:1032100079078CE692E00E9454070CCF82E0E82EFA
+:10322000F12C22CF80910701882309F46DCF8BE721
+:1032300098E00E94040768CF84159505A605B70598
+:1032400069F4F80180839183A283B383809107019D
+:10325000882309F459CF83E598E0EBCF4415550551
+:103260006605770571F4D8014D935D936D937C935A
+:10327000139780910701882309F446CF8BE298E0E9
+:10328000D8CF80E098E00E94EF05C7010E94A9070F
+:103290000C5F1F4FF2E0EF16F10409F0BFCF0E9460
+:1032A000FF08332433940E94E70600913204109102
+:1032B00033042091340430913504601B710B820B70
+:1032C000930B683E73408105910508F452C10E943A
+:1032D000E706609332047093330480933404909330
+:1032E0003504B8E0EB2EB1E0FB2E19EF812E13E090
+:1032F000912E49E154E05E874D8789E094E09C8BF4
+:103300008B8B6C015A0110E000E0202ED7018D91CB
+:103310009C91892B09F49EC0F60120813181D50151
+:103320008D919C912817390709F478C00E94E7060F
+:10333000F801EE0FFF1FEE0FFF1FE35EFB4F408013
+:103340005180628073809B01AC01241935094609C4
+:1033500057092F87388B498B5A8BD7012D913C9178
+:10336000E8EEF3E02E9FC0012F9F900D3E9F900D41
+:103370001124B0E0A0E04F84588869887A88481604
+:1033800059066A067B0608F449C0D5018D919C91C7
+:10339000F6019183808360E0802F0E94E10B8BEF28
+:1033A00098E00E94EF05C80101960E9479078EEE11
+:1033B00098E00E94EF050E94000780910701882392
+:1033C000A9F085ED98E00E94EF05C80101960E94E2
+:1033D000790784EE92E00E945407F7018081918181
+:1033E0000E94670786EE92E00E945B0721E040E0C2
+:1033F00050E0BA01822D0E94070880910D0490913F
+:103400000E04A0910F04B0911004F4018083918305
+:10341000A283B3831FC001E010E077CF40910D0479
+:1034200050910E0460910F0470911004F40180819A
+:103430009181A281B381481B590B6A0B7B0BD70189
+:103440008D919C91B0E0A0E0481759076A077B076F
+:1034500008F0B3CFF2E0EF0EF11C24E0820E911CD5
+:1034600032E0A30EB11C42E0C40ED11C01301105A4
+:1034700091F67CE0C72E71E0D72EE1E0EE2EE4E07D
+:10348000FE2E10E000E0D6012D913D916D01211539
+:10349000310509F448C0EB89FC8940815181AD8533
+:1034A000BE858D919C9148175907E9F140910D0413
+:1034B00050910E0460910F0470911004F701808107
+:1034C0009181A281B381481B590B6A0B7B0BFCE3F2
+:1034D000F29FC001F39F900D1124B0E0A0E04817C7
+:1034E00059076A077B07F8F060E0802F0E94E10B24
+:1034F00080910D0490910E04A0910F04B0911004DE
+:10350000F70180839183A283B38384E299E00E94D0
+:10351000EF05C80101960E94790782E199E00E94B7
+:10352000EF050E9400072B893C892E5F3F4F3C8BA3
+:103530002B8B4D855E854E5F5F4F5E874D8754E0D8
+:10354000E50EF11C0130110509F088C080910D04D1
+:1035500090910E04A0910F04B09110040196A11D4A
+:10356000B11D80930D0490930E04A0930F04B093AB
+:10357000100488E491E09E878D8757E2E52E54E0A1
+:10358000F52E6FE2C62E64E0D62E10E000E0702E1D
+:10359000AD85BE852D91BE87AD8730E0F901E35939
+:1035A000F64F8491F901E75AF64FB490F901EB5BBD
+:1035B000F64FA490AA2079F081110E942A06EA2DE4
+:1035C000F0E0EE0FFF1FE55CF64FA591B491EC9192
+:1035D000BE2281E009F480E0F60190818111BEC035
+:1035E000913009F041C00E94E706D7016D937D93A9
+:1035F0008D939C931397F801EB5DFB4F1082F601BE
+:103600001082B4E0EB0EF11CEFEFCE1ADE0A0130AF
+:10361000110539F58091180190911901892BA9F0B4
+:10362000809131048111BAC00E94FB0420911801DD
+:10363000309119018217930740F4309231040E94AF
+:10364000A90C89EE92E00E945B07A8950E9476057E
+:10365000882309F428CE0E94C10D25CE01E010E098
+:1036600012CF01E010E093CF9111CBCF0E94E7067B
+:10367000D7018D909D90AD90BC90AB01BC014819D5
+:1036800059096A097B098091160190911701092E49
+:10369000000CAA0BBB0B84179507A607B70708F009
+:1036A000B0CFF801EB5DFB4F5F0180818111A9CFA5
+:1036B0000E94E706D7016D937D938D939C9313979A
+:1036C000F50130820E94E7062801440C551C440C89
+:1036D000551CF201E35EFB4F80809180A280B38095
+:1036E0009B01AC01281939094A095B0949015A01B2
+:1036F0006083718382839383A801440F551FFA016D
+:10370000E75EFB4F208131812F5F3F4F3183208364
+:10371000405F5E4FDA014D915C9124173507B8F098
+:10372000D201AF5EBB4F4D915D916D917C9113972E
+:103730004F5F5F4F6F4F7F4F4D935D936D937C93C2
+:1037400013971182108260E0872D0E94640B21E0A4
+:10375000B501A401872D0E94070853CF911151CFC5
+:103760000E94E706F7014080518062807380AB01C0
+:10377000BC0144195509660977098091140190919B
+:103780001501092E000CAA0BBB0B84179507A60781
+:10379000B70708F036CFD6013C9233CF0E94FB0426
+:1037A00020911801309119012C5E3F4F28173907DD
+:1037B00008F04BCF1092310480E093E044CFE6E371
+:1037C000F4E01382128288EE93E0A0E0B0E08483FC
+:1037D0009583A683B78386E291E09183808385EC0D
+:1037E00090E09587848784EC90E09787868780ECCB
+:1037F00090E0918B808B81EC90E0938B828B82ECBC
+:1038000090E0958B848B86EC90E0978B868B118E65
+:10381000128E138E148E0895FC0188279927E89440
+:1038200021912032E9F3293010F02E30C8F32B32E9
+:1038300041F02D3239F4689404C00E949C1C820F20
+:10384000911D219120532A30C0F31EF4909581954B
+:103850009F4F08951F93FC0199278827BC01E89486
+:1038600011911032E9F3193010F01E30C8F31B32F9
+:1038700051F01D3249F4689406C00E94871C610F04
+:10388000711D811D911D119110531A30B0F33EF43A
+:1038900090958095709561957F4F8F4F9F4F1F91A9
+:1038A000089543ED54E00E94601C0895DC016C9182
+:1038B00061546A3108F060526F596D93C1F70895F1
+:1038C000FA01A191B081009719F41097E1F0CD01B0
+:1038D000DC01CD010D90002011F4C00113C0FB01EB
+:1038E0002191222319F02015D9F7F3CFFB01219163
+:1038F000201519F41E92119606C02223C1F70D90CF
+:103900000020A1F7D001FA01A193B0830895592FA7
+:10391000482F372F262F660F771F881F991F660F96
+:10392000771F881F991F620F731F841F951F660FD3
+:10393000771F881F991F08957AE0979F902D879F82
+:10394000802D910D11240895F999FECF92BD81BD6E
+:10395000F89A992780B50895A8E1B0E042E050E0D8
+:103960000C94C21C262FF999FECF1FBA92BD81BDBF
+:1039700020BD0FB6F894FA9AF99A0FBE01960895F1
+:10398000DC01CB01FC01F999FECF06C0F2BDE1BD1F
+:10399000F89A319600B40D9241505040B8F708950E
+:1039A000A1E21A2EAA1BBB1BFD010DC0AA1FBB1F43
+:1039B000EE1FFF1FA217B307E407F50720F0A21BB5
+:1039C000B30BE40BF50B661F771F881F991F1A9422
+:1039D00069F760957095809590959B01AC01BD014C
+:1039E000CF010895EE0FFF1F0590F491E02D09948B
+:1039F000FC018191861721F08823D9F79927089532
+:103A00003197CF010895FB01DC018D910190801960
+:103A10000110D9F3990B0895FB01DC01415050408E
+:103A200030F08D910190801919F40020B9F7881BAE
+:083A3000990B0895F894FFCFF3
+:103A380001010020002C000100002C010F000000F3
+:103A4800E803640046002800F401800080020002B8
+:103A5800800000000000A2050C0539050A066A0569
+:103A680048055C05120014000E0010000A000C0046
+:103A7800280034002400300002030D0A0030300012
+:103A88007D0043003B0064617461736574733A2080
+:103A98000020200900095900094E006D732E2E2EB2
+:103AA80000444F4E4500636D643A202700494400A6
+:103AB8004475616C5330496D70436F756E746572EF
+:103AC80000207600312E30006765742065657072BD
+:103AD8006F6D00736176652064617461006465626E
+:103AE80075672031006465627567203000666F7203
+:103AF8006D617420616C6C00666F726D6174206317
+:103B0800006765742072656164696E677300676534
+:103B18007420696D70206300676574207077726720
+:103B28006F6F640073657420707772676F6F6400DD
+:103B3800736574206A736F6E203000736574206A31
+:103B4800736F6E20310067657420636F6E66007353
+:103B58006574206465626F756E63650067657420BF
+:103B68006465626F756E6365002C20007365742050
+:103B7800636F6E66206300636D64446174614275AF
+:103B8800666665723A2027005F634E756D3D005F7B
+:103B9800634E756D20696E76616C69643A200069C0
+:103BA8006D70706572756E697400696D70506572BC
+:103BB800556E69743D006E6F696D70746F75740031
+:103BC8006E6F496D70546F75743D007361766569E9
+:103BD8006E740073617665496E743D007361766535
+:103BE80020636F6E66007365742072656164696E28
+:103BF80067005345542052454144494E470020210F
+:103C08002121006765742077636F756E7400726593
+:103C1800736574002800732900504F574552204996
+:103C28005320474F494E4720444F574E2E2E2E00C3
+:103C3800504F57455220524553544F5245442E2E0B
+:023C48002E004C
+:00000001FF

+ 244 - 0
Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/DualS0ImpCounter.ino

@@ -0,0 +1,244 @@
+/*
+  Dual Impulse Counter
+
+  Arduino/AVR software to detect 2 impulse inputs, increment counters and save counter values to EEPROM. 
+  With power loss detection / saving. 
+  
+  Copyright 2020 Florian Krauter
+  
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define SERIALBAUD 57600
+#define SERIALCONF SERIAL_8N1
+
+//#define INCLUDE_TESTFUNCTIONS
+
+#define PROJECT_NAME "DualS0ImpCounter"
+#define PROJECT_VERSION "1.0"
+
+#include <avr/wdt.h>
+#include <EEPROM.h>
+
+// DIGITAL OUTPUTS
+#define PIN_OUT_HARDRESET 6
+#define PIN_OUT_LED 13
+
+// DIGITAL INPUTS
+#define PIN_IN_PULSE1 2
+#define PIN_IN_PULSE2 3
+
+// NUMBER OF COUNTERS
+#define COUNTERS_COUNT 2
+
+// ANALOG INPUTS
+#define PIN_IN_ADC_PWRGOOD A3
+
+
+// global conf variables
+
+// POWER GOOD - monitors voltage in front of the onboard voltage regulator powering the AVR/Arduino
+// in order to save all data to EEPROM before power is really gone
+// to enable this, supply voltage is much higher than needed for an AVR/Arduino (9-12V)
+// connected to a huge (2200uF) capacitor over a decoupling diode (voltage drop 0.6-0.7V)
+// and regulated to Vcc=5V by the Arduino onboard regulator
+// Vin is measured through a voltage divider of 56k/24k (after the diode)
+// a value of 420 seems to be the minimum at ~7.5V supply voltage (in front of the decoupling diode)
+// below this the value increases again due to voltage regulator drop out and therefore sinking Vref
+// so a reasonable safety margin is mandatory here
+// as we use a 12V supply we set this to 500 for now ( ~= 9.0V)
+unsigned int powerGoodMinValue = 500; 
+int debounceDelay = 40;
+int debounceRecoveryDelay = 70;
+
+bool debug = true;
+int debuglevel = 1;
+bool output_json = true;
+
+// --- END global conf vars
+
+
+unsigned long currentReading[COUNTERS_COUNT];
+uint16_t currentReadingImpulses[COUNTERS_COUNT];
+uint16_t currentReadingImpulses_saved[COUNTERS_COUNT];
+
+byte pulseInPins[] = {PIN_IN_PULSE1, PIN_IN_PULSE2};
+byte pulseInLastState[2];
+unsigned long pulseInLastDebounceTime[] = {0, 0};
+
+bool pulseAlreadyDetected[COUNTERS_COUNT];
+unsigned long pulseInLastMillis[COUNTERS_COUNT];
+
+
+// config vars per counter
+uint16_t meter_impPerUnit[] = {1000, 100};
+uint16_t meter_noImpulseTimeout_seconds[] = {0, 300};
+uint16_t meter_savePulsesOnInterval_mins[] = {15, 0};
+//uint16_t meter_savePulsesEveryImpulses[] = {0, 0};
+
+
+// global vars
+unsigned long pulsesLastSaved_seconds[COUNTERS_COUNT];
+unsigned long lastDataSent_seconds[COUNTERS_COUNT];
+
+unsigned long lastSaveTime_pulses = 0;
+unsigned long millis_everysecond = 0;
+unsigned long seconds=0;
+
+// global static vars
+
+// serial commands
+#define MAX_CMD_LEN 120
+#define MAX_CMDDATA_LEN 90
+char cmdBuffer[MAX_CMD_LEN + 1];    // Serial Input-Buffer
+int cmdBufferCount = 0;    // Anzahl der eingelesenen Zeichen
+bool cmdComplete = false;
+char cmdDataBuffer[MAX_CMDDATA_LEN + 1];
+
+
+
+// EEPROM addresses
+
+// configuration values in EEPROM addr 0-19 (avoid using 0 so starting at 2)
+uint16_t eeprom_addr_debug = 2; // 1 byte
+uint16_t eeprom_addr_output_json = 3; // 1 byte
+uint16_t eeprom_addr_debounce1 = 4; // 2 byte
+uint16_t eeprom_addr_debounce2 = 6; // 2 byte
+uint16_t eeprom_addr_powerGoodMinValue = 8; // 2 byte
+
+uint16_t eeprom_addr_impPerUnit[] = {10, 12};  // 2 bytes
+uint16_t eeprom_addr_noImpTout[] = {14, 16}; // 2 bytes
+uint16_t eeprom_addr_saveInt[] = {18, 20}; // 2 bytes
+
+
+// 4 bytes (unsigned long) for current unit readings
+// use 3 EEPROM for each reading addresses (2 as backup, so that the actual value can hopefully always be restored when 2 of them hold the same value)
+// as the value ranges from 0 to max. 100000 here we can write this directly on every value change
+// reserved EEPROM addr: 20-68 (4 counters a 3 values a 4 bytes
+uint16_t eeprom_addr_currentReading[2] = {32, 44};
+uint16_t eeprom_addr_currentReading_backup1[2] = {36, 48};
+uint16_t eeprom_addr_currentReading_backup2[2] = {40, 52};
+
+// different situation on the impulses where 100 imp ^= 1 reading
+// these are updated quite often, so directly writing will bring troubles with EEPROM endurance
+// this value has to be written:
+//   - after every increment of main reading value (set to 0, to ensure it will not hold a higher than real count)
+//   - after some time of no impulse counter change (to save from time to time so that we don´t loose too many impulses)
+//   -> When logging a gas meter this should be sufficient, as these typically stand still for a longer period between consuming periods as the heating
+//      is switched in intervals.
+//      as these typically have 10 or 100 pulses per unit (m^3), it should be safe to just write every reading rollover
+//      (without decimals/single impulses) and + write the current impulse count when there was no activity for some minutes.
+//      When logging i.e. a power meter with 1000 imp/kWh, it would get more complicated. These typically don´t ever stand still, so only writing
+//      the current pulse count when there is no activity would just not work. Also 1000 pulses are a lot to loose, so for this case it is necessary
+//      to also write i.E. every 50st or 100st pulse or every 10-60 min additionally.
+//   -> this all leads to a somehow higher write load
+//      so using wear leveling is advisable
+//      a simple approach to that (ring buffer):
+//        - define an address area on the EEPROM for this use
+//        - preformat the entire EEPROM area (write 0x00 to every byte)
+//        - before every EEPROM write, increase a 2 byte (uint16_t) write counter
+//        - use this counter as offset to point to the actual most current data (has to multiplied with the length one dataset uses for sure)
+//        - memorize last address written and write next dataset to the next address
+//        - store the writecounter and the data next to it (examples for 2 byte counter and 2 byte data):
+//            EEPROM area start address: 128
+//            counter=0 -> addr 128+129, value -> addr 130+131    (=start_addr + (counter * 4) => 128 + (0*4) = 128
+//            counter=1 -> addr 132+133, value -> addr 134+135    (=start_addr + (counter * 4) => 128 + (1*4) = 132
+//            counter=2 -> addr 136+137, value -> addr 138+139    (=start_addr + (counter * 4) => 128 + (2*4) = 136
+//        - repeat writing at offset 0 when the entire address space is used
+//        - when restoring data, scan the entire area to find the position where the writecounter value is > than writecounter in the next field
+//          and restore data from that position
+//
+
+static byte eeprom_datasetsize_currentReadingImpulses = 4;  // 2 bytes data, 2 bytes write counter
+uint16_t eeprom_addr_area_start_currentReadingImpulses[2] = {128, 640};
+uint16_t eeprom_addr_area_length_currentReadingImpulses[2] = {512, 128};
+
+uint16_t eeprom_writecounter_currentReadingImpulses[COUNTERS_COUNT];
+uint16_t eeprom_nextoffset_currentReadingImpulses[COUNTERS_COUNT];
+
+
+/**
+   Setup.
+*/
+void setup() {
+  // immediately disable watchdog timer so we will not get interrupted
+  wdt_disable();
+
+  // init global vars/arrays
+  for (int i = 0; i < COUNTERS_COUNT; i++) {
+    eeprom_writecounter_currentReadingImpulses[i] = 0;
+    eeprom_nextoffset_currentReadingImpulses[i] = 0;
+    currentReading[i] = 0;
+    pulseInLastMillis[i] = 0;
+    pulseAlreadyDetected[i] = false;
+  }
+
+  // PIN_OUT_HARDRESET is wired to /RESET PIN
+  // used to hard reset the MCU from software
+  // when there is no DTS pin connected and a firmware update should be installed
+  // normally set to INPUT mode (without pullup, so "no" connection to the actual RESET pin)
+  pinMode(PIN_OUT_HARDRESET, INPUT);
+  pinMode(PIN_IN_PULSE1, INPUT_PULLUP);
+  pinMode(PIN_IN_PULSE2, INPUT_PULLUP);
+  
+  // the following forces a pause before enabling WDT. This gives the IDE a chance to
+  // call the bootloader in case something dumb happens during development and the WDT
+  // resets the MCU too quickly. Once the code is solid, remove this.
+  delay(2L * 1000L);
+
+  // enable the watchdog timer. There are a finite number of timeouts allowed (see wdt.h).
+  // Notes I have seen say it is unwise to go below 250ms as you may get the WDT stuck in a
+  // loop rebooting.
+  // The timeouts I'm most likely to use are:
+  // WDTO_1S
+  // WDTO_2S
+  // WDTO_4S
+  // WDTO_8S
+  wdt_enable(WDTO_8S);
+
+  Serial.begin(SERIALBAUD, SERIALCONF);
+  Serial.print(PROJECT_NAME);
+  Serial.print(" v");
+  Serial.print(PROJECT_VERSION);
+  Serial.print(F(" starting..."));
+
+  // read config from EEPROM
+  loadConfig();
+
+  // restore counters from EEPROM
+  restoreAllLastData();
+
+  // output current counter values
+  printAllCurrentReadings();
+  
+}
+
+void loop() {
+  if ((millis() - millis_everysecond) >= 1000) {
+    millis_everysecond = millis();
+    everySecond();
+  }
+
+  checkInputStates();
+
+  checkPowerGood();
+
+  wdt_reset();
+}
+
+void everySecond() {
+  onNoImpulseTimeout();
+  saveDataOnInterval();
+  seconds++;
+}

+ 127 - 0
Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/counterFunctions.ino

@@ -0,0 +1,127 @@
+
+void increaseCounter(byte _cNum) {
+  unsigned long _deltaTime;
+  unsigned long _currMillis;
+
+  _currMillis = millis();
+  _deltaTime = _currMillis - pulseInLastMillis[_cNum];
+  pulseInLastMillis[_cNum] = _currMillis;
+
+  currentReadingImpulses[_cNum]++;
+  if (currentReadingImpulses[_cNum] >= meter_impPerUnit[_cNum]) {
+    currentReading[_cNum]++;
+    currentReadingImpulses[_cNum] = 0;
+    storeCurrentReading(_cNum, false);
+  }
+  printCurrentReading(_cNum, _deltaTime, true);
+}
+
+
+void printCurrentReadings() {
+  for (byte i = 0; i < COUNTERS_COUNT; i++) {
+    printCurrentReading(i, 0, false);
+  }
+}
+
+void printCurrentReading(byte _cNum, unsigned long _deltaTime, bool _sendDeltaTime) {
+  if (output_json) {
+    Serial.print(F("{\"C\":"));
+    Serial.print(_cNum + 1);
+    Serial.print(F(", \"reading\":"));
+    Serial.print(currentReading[_cNum]);
+    Serial.print(".");
+    if (meter_impPerUnit[_cNum] == 100 && currentReadingImpulses[_cNum] < 10) Serial.print("0");
+    else if (meter_impPerUnit[_cNum] == 1000 && currentReadingImpulses[_cNum] < 10) Serial.print("00");
+    else if (meter_impPerUnit[_cNum] == 1000 && currentReadingImpulses[_cNum] < 100) Serial.print("0");
+    Serial.print(currentReadingImpulses[_cNum]);
+
+    Serial.print(F(", \"impPerU\":"));
+    Serial.print(meter_impPerUnit[_cNum]);
+      
+    if (_sendDeltaTime) {
+      Serial.print(F(", \"dTime\":"));
+      Serial.print(_deltaTime);
+    }
+    Serial.println("}");
+  }
+  else {
+    Serial.print("C");
+    Serial.print(_cNum + 1);
+    Serial.print("=");
+    Serial.print(currentReading[_cNum]);
+    Serial.print(".");
+    if (meter_impPerUnit[_cNum] == 100 && currentReadingImpulses[_cNum] < 10) Serial.print("0");
+    else if (meter_impPerUnit[_cNum] == 1000 && currentReadingImpulses[_cNum] < 10) Serial.print("00");
+    else if (meter_impPerUnit[_cNum] == 1000 && currentReadingImpulses[_cNum] < 100) Serial.print("0");
+    Serial.print(currentReadingImpulses[_cNum]);
+    Serial.print(";");
+    Serial.print(meter_impPerUnit[_cNum]);
+    if (_sendDeltaTime) {
+      Serial.print(";");
+      Serial.print(_deltaTime);
+    }
+    Serial.println();
+  }
+  lastDataSent_seconds[_cNum] = seconds;
+}
+
+
+
+void onNoImpulseTimeout() {
+  for (byte i = 0; i < COUNTERS_COUNT; i++) {
+    if (meter_noImpulseTimeout_seconds[i] > 0) {
+      bool _sendDataNow = false;
+      
+      // store counter to EEPROM if value changed
+      if ( (currentReadingImpulses_saved[i] != currentReadingImpulses[i]) && ((millis() - pulseInLastMillis[i]) >= (meter_noImpulseTimeout_seconds[i] * 1000)) ) {
+        currentReadingImpulses_saved[i] = currentReadingImpulses[i];
+        storeCurrentImpulses(i, false);
+        Serial.print(F("INFO: saved impCount C"));
+        Serial.print(i + 1);
+        Serial.print(F(" (noImpTout)"));
+        Serial.println();
+        _sendDataNow = true;
+      }
+
+
+      // send current data with current usage=0 on interval
+      if ( _sendDataNow || (seconds - lastDataSent_seconds[i]) >= meter_noImpulseTimeout_seconds[i] ) {
+        if(debug) {
+          Serial.print(F("send data on noImpTout C"));
+          Serial.print(i + 1);
+          Serial.print("(");
+          Serial.print(meter_noImpulseTimeout_seconds[i]);
+          Serial.println("s)");
+        }
+        printCurrentReading(i, 0, true);
+        lastDataSent_seconds[i] = seconds;
+      }
+    }
+  }
+}
+
+
+
+void saveDataOnInterval() {
+  for (byte i = 0; i < COUNTERS_COUNT; i++) {
+    if (meter_savePulsesOnInterval_mins[i] > 0 && (currentReadingImpulses_saved[i] != currentReadingImpulses[i])) {
+      if ((seconds - pulsesLastSaved_seconds[i]) >= (meter_savePulsesOnInterval_mins[i] * 60)) {
+        storeCurrentImpulses(i, false);
+        pulsesLastSaved_seconds[i] = seconds;
+        Serial.print(F("INFO: saved impCount C"));
+        Serial.print(i + 1);
+        Serial.print(F(" (fixed interval)"));
+        Serial.println();
+      }
+    }
+  }
+}
+
+
+
+/*void printImpPerUnit(byte _cNum) {
+  Serial.print("C");
+  Serial.print(_cNum + 1);
+  Serial.print(F(": imp/unit="));
+  Serial.println(meter_impPerUnit[_cNum]);
+}*/

+ 60 - 0
Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/eeprom_functions.ino

@@ -0,0 +1,60 @@
+
+void getEEPROMContent() {
+  int eeprom_address = 0;
+  byte eeprom_value;
+  Serial.println(F("EEPROM-Data:"));
+  Serial.println(F("ADDR\t0\t1\t2\t3\t4\t5\t6\t7"));
+  int col = 0;
+  for (int i = 0; i < EEPROM.length(); i++) {
+    eeprom_value = EEPROM.read(eeprom_address);
+    if (col == 0) {
+      Serial.print(eeprom_address);
+      Serial.print("\t");
+    }
+    Serial.print(eeprom_value, DEC);
+    Serial.print("\t");
+    eeprom_address = eeprom_address + 1;
+
+    if (col >= 7) {
+      col = 0;
+      Serial.println();
+    }
+    else col++;
+  }
+}
+
+void formatEEPROMArea(int _from, int _len) {
+  int _to;
+  _to = _from + _len - 1;
+  Serial.print(F("EEPROM - formatting area from "));
+  Serial.print(_from);
+  Serial.print(F(" to "));
+  Serial.println(_to);
+  for (int i = _from; i <= _to; i++) {
+    Serial.print(".");
+    EEPROM.update(i, 0);
+  }
+  Serial.println("DONE");
+}
+
+
+void formatEEPROM_AllData() {
+  for (byte i = 0; i < COUNTERS_COUNT; i++) {
+    formatEEPROMArea(eeprom_addr_area_start_currentReadingImpulses[i], eeprom_addr_area_length_currentReadingImpulses[i]);
+    formatEEPROMArea(eeprom_addr_currentReading[i], 4);
+    formatEEPROMArea(eeprom_addr_currentReading_backup1[i], 4);
+    formatEEPROMArea(eeprom_addr_currentReading_backup2[i], 4);
+  }
+}
+
+
+void formatEEPROMAreaOfCounter(byte _cNum) {
+  if (_cNum >= 0 && _cNum < COUNTERS_COUNT) {
+    formatEEPROMArea(eeprom_addr_currentReading[_cNum], 4);
+    formatEEPROMArea(eeprom_addr_currentReading_backup1[_cNum], 4);
+    formatEEPROMArea(eeprom_addr_currentReading_backup2[_cNum], 4);
+    formatEEPROMArea(eeprom_addr_area_start_currentReadingImpulses[_cNum], eeprom_addr_area_length_currentReadingImpulses[_cNum]);
+    eeprom_nextoffset_currentReadingImpulses[_cNum] = 0;
+    eeprom_writecounter_currentReadingImpulses[_cNum] = 1;
+  }
+}

+ 232 - 0
Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/eeprom_storeRetrieveConfig.ino

@@ -0,0 +1,232 @@
+void loadConfig() {
+
+  Serial.println();
+  //Serial.println(F("LOADING CONFIG..."));
+  uint16_t tmpint = 0;
+  byte tmpbyte;
+
+  Serial.println(F("loading global conf:"));
+
+  EEPROM.get(eeprom_addr_debug, tmpbyte);
+  Serial.print(F("debuglevel: "));
+  if (tmpbyte == 0 || tmpbyte == 1) {
+    debuglevel = tmpbyte;
+    Serial.print(debuglevel);
+    if (debuglevel == 0) debug = false;
+    else if (debuglevel == 1) debug = true;
+  }
+  else {
+    Serial.print(tmpbyte);
+    Serial.println(F(" - invalid value stored"));
+  }
+  Serial.println();
+
+
+  EEPROM.get(eeprom_addr_output_json, tmpbyte);
+  Serial.print(F("json: "));
+  if (tmpbyte == 0 || tmpbyte == 1) {
+    Serial.println(tmpbyte);
+    if (tmpbyte == 1) output_json = true;
+    else if (tmpbyte == 0) output_json = false;
+
+  }
+  else {
+    Serial.print(tmpbyte);
+    Serial.println(F(" - invalid value stored"));
+  }
+
+
+
+  EEPROM.get(eeprom_addr_debounce1, tmpint);
+  Serial.print(F("debounce1: "));
+  if (tmpint >= 0 && tmpint <= 200) {
+    debounceDelay = tmpint;
+    Serial.println(debounceDelay);
+  }
+  else {
+    Serial.println(F("invalid value stored"));
+  }
+
+  EEPROM.get(eeprom_addr_debounce2, tmpint);
+  Serial.print(F("debounce2: "));
+  if (tmpint >= 0 && tmpint <= 500) {
+    debounceRecoveryDelay = tmpint;
+    Serial.println(debounceRecoveryDelay);
+  }
+  else {
+    Serial.println(F("invalid value stored"));
+  }
+
+  EEPROM.get(eeprom_addr_powerGoodMinValue, tmpint);
+  Serial.print(F("pwrGood: "));
+  if (tmpint >= 0 && tmpint <= 1023) {
+    powerGoodMinValue = tmpint;
+    Serial.println(powerGoodMinValue);
+  }
+  else {
+    Serial.println(F("invalid value stored"));
+  }
+
+  Serial.println();
+
+  // per counter
+  Serial.println(F("loading counters conf:"));
+  for (byte i = 0; i < COUNTERS_COUNT; i++) {
+    Serial.println();
+    Serial.print("C");
+    Serial.print(i + 1);
+    Serial.print(": ");
+
+    EEPROM.get(eeprom_addr_impPerUnit[i], tmpint);
+    Serial.print(F("impPerUnit="));
+    Serial.print(tmpint);
+    if (tmpint == 10 || tmpint == 100 || tmpint == 1000) {
+      meter_impPerUnit[i] = tmpint;
+    }
+    else {
+      Serial.println();
+      Serial.print(F("WARNING: C"));
+      Serial.print(i + 1);
+      Serial.println(F(" config impPerUnit is invalid!"));
+      Serial.print("C");
+      Serial.print(i + 1);
+      Serial.print(": ");
+    }
+
+    EEPROM.get(eeprom_addr_noImpTout[i], tmpint);
+    Serial.print(F(", noImpTout="));
+    Serial.print(tmpint);
+
+    if (tmpint >= 0 && tmpint <= 3600) {
+      meter_noImpulseTimeout_seconds[i] = tmpint;
+    }
+    else {
+      Serial.println();
+      Serial.print(F("WARNING: C"));
+      Serial.print(i + 1);
+      Serial.println(F(" config noImpTout is invalid (out of range 0-3600)!"));
+      Serial.print("C");
+      Serial.print(i + 1);
+      Serial.print(": ");
+    }
+
+    EEPROM.get(eeprom_addr_saveInt[i], tmpint);
+    Serial.print(F(", saveInt="));
+    Serial.print(tmpint);
+    if (tmpint >= 0 && tmpint <= 3600) {
+      meter_savePulsesOnInterval_mins[i] = tmpint;
+    }
+    else {
+      Serial.println();
+      Serial.print(F("WARNING: C"));
+      Serial.print(i + 1);
+      Serial.println(F(" config saveInt is invalid (out of range 0-3600)!"));
+      Serial.print("C");
+      Serial.print(i + 1);
+      Serial.print(": ");
+    }
+
+  }
+
+  Serial.println();
+}
+
+
+void printCounterConf(byte _cNum) {
+  Serial.print(F("CONF C"));
+  Serial.print(_cNum + 1);
+  Serial.print(F(": impPerUnit="));
+  Serial.print(meter_impPerUnit[_cNum]);
+
+  Serial.print(F(", noImpTout="));
+  Serial.print(meter_noImpulseTimeout_seconds[_cNum]);
+
+  Serial.print(F(", saveInt="));
+  Serial.print(meter_savePulsesOnInterval_mins[_cNum]);
+
+  Serial.println();
+}
+
+void printGlobalConf() {
+  Serial.print(F("CONF GLOB: debuglevel="));
+  Serial.print(debuglevel);
+
+  Serial.print(F(", debounce="));
+  Serial.print(debounceDelay);
+
+  Serial.print(F(", debRecov="));
+  Serial.print(debounceRecoveryDelay);
+
+  Serial.print(F(", pwrGood="));
+  Serial.print(powerGoodMinValue);
+
+  Serial.println();
+
+}
+
+void saveGlobalConfig() {
+  Serial.println(F("SAVING GLOBAL CONFIG"));
+
+  if (debounceDelay >= 0 && debounceDelay <= 200) {
+    EEPROM.put(eeprom_addr_debounce1, debounceDelay);
+  }
+
+  if (debounceRecoveryDelay >= 0 && debounceRecoveryDelay <= 500) {
+    EEPROM.put(eeprom_addr_debounce2, debounceRecoveryDelay);
+  }
+
+  if (powerGoodMinValue >= 0 && powerGoodMinValue <= 1023) {
+    EEPROM.put(eeprom_addr_powerGoodMinValue, powerGoodMinValue);
+  }
+
+
+
+}
+
+void saveCountersConfig() {
+  for (byte i = 0; i < COUNTERS_COUNT; i++) {
+
+    Serial.print(F("SAVING C"));
+    Serial.print(i + 1);
+    Serial.print(F(" - impPerUnit="));
+    Serial.println(meter_impPerUnit[i]);
+    if (meter_impPerUnit[i] == 10 || meter_impPerUnit[i] == 100 || meter_impPerUnit[i] == 1000) {
+      EEPROM.put(eeprom_addr_impPerUnit[i], meter_impPerUnit[i]);
+    }
+    else {
+      Serial.print(F("WARNING: C"));
+      Serial.print(i + 1);
+      Serial.println(F(" config 'impPerUnit' invalid! Did not save."));
+    }
+
+
+    Serial.print(F("SAVING C"));
+    Serial.print(i + 1);
+    Serial.print(F(" - noImpTout="));
+    Serial.println(meter_noImpulseTimeout_seconds[i]);
+    if (meter_noImpulseTimeout_seconds[i] >= 0 && meter_noImpulseTimeout_seconds[i] <= 3600) {
+      EEPROM.put(eeprom_addr_noImpTout[i], meter_noImpulseTimeout_seconds[i]);
+    }
+    else {
+      Serial.print(F("WARNING: C"));
+      Serial.print(i + 1);
+      Serial.println(F(" config 'noImpTout' invalid! Did not save."));
+    }
+
+
+    Serial.print(F("SAVING C"));
+    Serial.print(i + 1);
+    Serial.print(F(" - noImpTout="));
+    Serial.println(meter_savePulsesOnInterval_mins[i]);
+    if (meter_savePulsesOnInterval_mins[i] >= 0 && meter_savePulsesOnInterval_mins[i] <= 3600) {
+      EEPROM.put(eeprom_addr_saveInt[i], meter_savePulsesOnInterval_mins[i]);
+    }
+    else {
+      Serial.print(F("WARNING: C"));
+      Serial.print(i + 1);
+      Serial.println(F(" config 'noImpTout' invalid! Did not save."));
+    }
+
+  }
+
+}

+ 290 - 0
Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/eeprom_storeRetrieveCounters.ino

@@ -0,0 +1,290 @@
+
+void storeCurrentReading(byte _cNum, boolean _force) {
+  if (_cNum >= 0 && _cNum < COUNTERS_COUNT) {
+    int _currentEEPROMValue;
+    _currentEEPROMValue = (int)eeprom_read_word(&eeprom_addr_currentReading[_cNum]);
+    if (_currentEEPROMValue != currentReading[_cNum] || _force) {
+      //eeprom_write_word(&eeprom_addr_currentReading[cNum], currentReading[cNum]);
+      EEPROM.put(eeprom_addr_currentReading[_cNum], currentReading[_cNum]);
+      EEPROM.put(eeprom_addr_currentReading_backup1[_cNum], currentReading[_cNum]);
+      EEPROM.put(eeprom_addr_currentReading_backup2[_cNum], currentReading[_cNum]);
+      Serial.println(F("INFO: Saved current reading to EEPROM."));
+    }
+    //storeCurrentImpulses(_cNum, false);
+  }
+}
+
+
+
+void restoreLastReading(byte _cNum) {
+  //currentReading = (int)eeprom_read_word(&eeprom_addr_currentReading);
+  unsigned long _currentReading, _currentReading_backup1, _currentReading_backup2;
+  uint16_t _currentImpulsesCount;
+  EEPROM.get(eeprom_addr_currentReading[_cNum], _currentReading);
+  EEPROM.get(eeprom_addr_currentReading_backup1[_cNum], _currentReading_backup1);
+  EEPROM.get(eeprom_addr_currentReading_backup2[_cNum], _currentReading_backup2);
+  bool _restoredReading = false;
+
+  if (debug) {
+    Serial.println();
+    Serial.println();
+    Serial.print(F("trying to restore last reading for C"));
+    Serial.print(_cNum + 1);
+    Serial.println("...");
+  }
+
+  if (_currentReading == _currentReading_backup1 && _currentReading == _currentReading_backup2) {
+    // all good - take the value and go
+    currentReading[_cNum] = _currentReading;
+    _restoredReading = true;
+    //if(debug) Serial.println(F("All stored readings are equal"));
+  }
+  else if ( (_currentReading == _currentReading_backup1) ) {
+    // OK, 2 values are identical - go on
+    currentReading[_cNum] = _currentReading;
+    _restoredReading = true;
+    if (debug) Serial.println(F("INFO: stored readings 1 and 2 are equal"));
+  }
+  else if ( (_currentReading == _currentReading_backup2) ) {
+    // OK, 2 values are identical - go on
+    currentReading[_cNum] = _currentReading;
+    _restoredReading = true;
+    if (debug) Serial.println(F("INFO: stored readings 1 and 3 are equal"));
+  }
+  else if ( (_currentReading_backup1 == _currentReading_backup2) ) {
+    // OK, 2 values are identical - go on
+    currentReading[_cNum] = _currentReading_backup1;
+    _restoredReading = true;
+    if (debug) Serial.println(F("INFO: stored readings 2 and 3 are equal"));
+  }
+  else {
+    // not good - all stored values are different, so we don´t know which one is right
+    Serial.print(F("ERROR: FAILED to restore last reading of C"));
+    Serial.println(_cNum + 1);
+    //printCurrentReading(_cNum);
+  }
+
+  if (_restoredReading) {
+    //Serial.print(F("Restored reading: "));
+    //Serial.print(currentReading);
+    //Serial.print(".");
+    //Serial.print(currentReadingImpulses);
+    //Serial.println();
+    Serial.print(F("INFO: restored reading of C"));
+    Serial.print(_cNum + 1);
+    Serial.print("=");
+    Serial.println(currentReading[_cNum]);
+    //printCurrentReading(_cNum);
+  }
+}
+
+
+
+void restoreAllLastData() {
+  for (byte i = 0; i < COUNTERS_COUNT; i++) {
+    restoreLastSavedImpulseCount(i, false);
+    restoreLastReading(i);
+  }
+}
+
+
+
+void printAllCurrentReadings() {
+  for (byte i = 0; i < COUNTERS_COUNT; i++) {
+    printCurrentReading(i, 0, false);
+  }
+}
+
+
+void saveAllCurrentData(bool _force) {
+  for (byte i = 0; i < COUNTERS_COUNT; i++) {
+    storeCurrentImpulses(i, false);
+    //if (_force) storeCurrentReading(i, true);
+    storeCurrentReading(i, false);
+  }
+  Serial.println(F("INFO: saved all current data."));
+}
+
+
+
+void restoreLastSavedImpulseCount(byte _cNum, bool _printOnly) {
+  uint16_t _datasets, _offset, _addr, _maxAddrOffset, _nextOffset;
+  uint16_t _lastWriteCounter = 0;
+  uint16_t _currentWriteCounter = 0;
+  uint16_t _currentData = 0;
+  uint16_t _found_writeCounter = 0;
+  uint16_t _found_data = 0;
+  uint16_t _found_offset = 0;
+  bool _foundData = false;
+
+  if (debug || _printOnly) {
+    Serial.println();
+    Serial.println();
+    Serial.print(F("trying to restore last impulses count for C"));
+    Serial.print(_cNum + 1);
+    Serial.println("...");
+  }
+
+  _datasets = eeprom_addr_area_length_currentReadingImpulses[_cNum] / eeprom_datasetsize_currentReadingImpulses;
+  if (debug || _printOnly) {
+    Serial.print("datasets: ");
+    Serial.println(_datasets);
+    Serial.println(F("dSet\toffset\taddr\twC\tlwC\tdata\tvalid"));
+  }
+
+  // iterate over the EEPROM data area to find the dataset with the highest writecounter
+  for (int i = 0; i < _datasets; i++) {
+    _offset = i * eeprom_datasetsize_currentReadingImpulses;
+    _addr = eeprom_addr_area_start_currentReadingImpulses[_cNum] + _offset;
+    if (debug || _printOnly) {
+      Serial.print((_offset / eeprom_datasetsize_currentReadingImpulses) + 1);
+      Serial.print("  \t");
+      Serial.print(_offset);
+      Serial.print("  \t");
+      Serial.print(_addr);
+    }
+
+    if (i > 0) {
+      _lastWriteCounter = _currentWriteCounter;
+    }
+
+    EEPROM.get(_addr, _currentWriteCounter);
+    EEPROM.get(_addr + 2, _currentData);
+
+    if (debug || _printOnly) {
+      Serial.print("  \t");
+      Serial.print(_currentWriteCounter);
+      Serial.print("\t");
+      Serial.print(_lastWriteCounter);
+      Serial.print("\t");
+      Serial.print(_currentData);
+    }
+
+    if ( i == 0 && _currentWriteCounter > 0) {
+      // find data in first dataset
+      _found_offset = _offset;
+      _found_writeCounter = _currentWriteCounter;
+      _found_data = _currentData;
+      _foundData = true;
+      if (debug || _printOnly) Serial.print("\tY");
+    }
+    else if (_currentWriteCounter == (_lastWriteCounter + 1)) {
+      // this dataset holds valid data
+      if (debug || _printOnly) Serial.print("\tY");
+      _found_offset = _offset;
+      _found_writeCounter = _currentWriteCounter;
+      _found_data = _currentData;
+      _foundData = true;
+    }
+    else {
+      // stop the for loop as we already found what we were looking for
+      // (or did not find anything)
+      i = _datasets + 1;
+      if (debug || _printOnly) Serial.print("\tN");
+    }
+
+    if (debug || _printOnly) Serial.println();
+
+  }
+
+  if (!_foundData) {
+    if (debug || _printOnly) {
+      Serial.print(F("NOTHING FOUND - EEPROM area seems empty for C"));
+      Serial.println(_cNum + 1);
+    }
+
+    if (!_printOnly) {
+      eeprom_nextoffset_currentReadingImpulses[_cNum] = 0;
+      eeprom_writecounter_currentReadingImpulses[_cNum] = 1;
+    }
+  }
+  else {
+    _maxAddrOffset = eeprom_addr_area_length_currentReadingImpulses[_cNum] - eeprom_datasetsize_currentReadingImpulses;
+    if ((_found_offset + eeprom_datasetsize_currentReadingImpulses) > _maxAddrOffset) {
+      _nextOffset = 0;
+    }
+    else _nextOffset = _found_offset + eeprom_datasetsize_currentReadingImpulses;
+
+    if (!_printOnly) {
+      eeprom_nextoffset_currentReadingImpulses[_cNum] = _nextOffset;
+      eeprom_writecounter_currentReadingImpulses[_cNum] = _found_writeCounter;
+      currentReadingImpulses[_cNum] = _found_data;
+      currentReadingImpulses_saved[_cNum] = _found_data;
+      Serial.print(F("INFO: restored impulse counter of C"));
+    }
+    else {
+      if (debug || _printOnly) Serial.print(F("INFO: printing stored impulse counter of C"));
+    }
+
+    //if (debug || _printOnly) {
+    Serial.print(_cNum + 1);
+    Serial.print(F(": data="));
+    Serial.print(_found_data);
+    if (debug || _printOnly) {
+      Serial.print(F(", wCount="));
+      Serial.print(_found_writeCounter);
+      Serial.print(F(", dSet="));
+      Serial.print((_found_offset / eeprom_datasetsize_currentReadingImpulses) + 1);
+      Serial.print(F(", offset="));
+      Serial.print(_found_offset);
+      Serial.print(F(", nOffset="));
+      Serial.println(_nextOffset);
+    }
+    else Serial.println();
+    //}
+  }
+  //getCurrentReading();
+}
+
+
+
+void storeCurrentImpulses(byte _cNum, bool _force) {
+  if (_force || (currentReadingImpulses_saved[_cNum] != currentReadingImpulses[_cNum])) {
+    uint16_t _addr, _nextAddrOffset, _maxAddrOffset, _datasets;
+
+    if (eeprom_writecounter_currentReadingImpulses[_cNum] == 65535) {
+      // if this write rolls over the writecounter variable (uint16_t)
+      // set write counter to 1 (0 is defined invalid) and write to offset 0
+      eeprom_writecounter_currentReadingImpulses[_cNum] = 1;
+      eeprom_nextoffset_currentReadingImpulses[_cNum] = 0;
+    }
+    else {
+      eeprom_writecounter_currentReadingImpulses[_cNum]++;
+    }
+
+    _addr = eeprom_addr_area_start_currentReadingImpulses[_cNum] + eeprom_nextoffset_currentReadingImpulses[_cNum];
+
+    if (debug) {
+      Serial.print(F("storeCurrentImpulses: C"));
+      Serial.print(_cNum + 1);
+      Serial.print(F("  data="));
+      Serial.print(currentReadingImpulses[_cNum]);
+      Serial.print(F(", wCount="));
+      Serial.print(eeprom_writecounter_currentReadingImpulses[_cNum]);
+      Serial.print(F(", offset="));
+      Serial.print(eeprom_nextoffset_currentReadingImpulses[_cNum]);
+      Serial.print(F(", dSet="));
+      Serial.println((eeprom_nextoffset_currentReadingImpulses[_cNum] / eeprom_datasetsize_currentReadingImpulses) + 1);
+    }
+
+    // write data first, then writecounter, in case a power failure occurs
+    EEPROM.put(_addr + 2, currentReadingImpulses[_cNum]);
+    EEPROM.put(_addr, eeprom_writecounter_currentReadingImpulses[_cNum]);
+
+    Serial.println(F("INFO: saved current pulses count to EEPROM"));
+    currentReadingImpulses_saved[_cNum] = currentReadingImpulses[_cNum];
+
+    pulsesLastSaved_seconds[_cNum] = seconds;
+
+    //_datasets = eeprom_addr_area_length_currentReadingImpulses[_cNum] / eeprom_datasetsize_currentReadingImpulses;
+    _nextAddrOffset = eeprom_nextoffset_currentReadingImpulses[_cNum] + eeprom_datasetsize_currentReadingImpulses;
+    _maxAddrOffset = eeprom_addr_area_length_currentReadingImpulses[_cNum] - eeprom_datasetsize_currentReadingImpulses;
+
+    if (_nextAddrOffset > _maxAddrOffset) {
+      eeprom_nextoffset_currentReadingImpulses[_cNum] = 0;
+    }
+    else {
+      eeprom_nextoffset_currentReadingImpulses[_cNum] = _nextAddrOffset;
+    }
+  }
+}

+ 23 - 0
Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/impulseInputs.ino

@@ -0,0 +1,23 @@
+void checkInputStates() {
+  for (byte i = 0; i < sizeof(pulseInPins); i++) {
+    byte _inputCurrentState = digitalRead(pulseInPins[i]);
+    if (_inputCurrentState == LOW && pulseInLastState[i] == HIGH) {
+      pulseInLastDebounceTime[i] = millis();
+      pulseAlreadyDetected[i] = false;
+      pulseInLastState[i] = _inputCurrentState;
+    }
+    else if (_inputCurrentState == LOW && pulseInLastState[i] == LOW) {
+      if ( (millis() - pulseInLastDebounceTime[i]) > debounceDelay && !pulseAlreadyDetected[i]) {
+        //if ( (millis() - pulseInLastDebounceTime[i]) > debounceDelay ) {
+        pulseInLastDebounceTime[i] = millis();
+        pulseAlreadyDetected[i] = true;
+        increaseCounter(i);
+      }
+    }
+    else if (_inputCurrentState == HIGH && pulseInLastState[i] == LOW) {
+      if ( (millis() - pulseInLastDebounceTime[i]) > debounceRecoveryDelay ) {
+        pulseInLastState[i] = _inputCurrentState;
+      }
+    }
+  }
+}

+ 30 - 0
Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/powerGood.ino

@@ -0,0 +1,30 @@
+unsigned long lastPwrCheck_millis = 0;
+boolean powerOut = false;
+
+void checkPowerGood() {
+  //if ((millis() - lastPwrCheck_millis) >= 1000) {
+  //  Serial.println(analogRead(A3));
+  //  lastPwrCheck_millis=millis();
+  //}
+  if (powerGoodMinValue > 0) {
+    if (!powerOut && analogRead(PIN_IN_ADC_PWRGOOD) < powerGoodMinValue) {
+      powerOut = true;
+      saveAllCurrentData(false);
+      Serial.println("POWER IS GOING DOWN...");
+      //doHardreset();
+    }
+    else if (powerOut && analogRead(PIN_IN_ADC_PWRGOOD) > (powerGoodMinValue + 20)) {
+      powerOut = false;
+      Serial.println("POWER RESTORED...");
+    }
+  }
+
+}
+
+void printPowerValue() {
+  Serial.print(F("POWER: pwrCurr="));
+  Serial.print(analogRead(PIN_IN_ADC_PWRGOOD));
+  Serial.print(F(", pwrGood="));
+  Serial.print(powerGoodMinValue);
+  Serial.println();
+}

+ 26 - 0
Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/resetForFlashing.ino

@@ -0,0 +1,26 @@
+
+void resetForFlashing(int afterms) {
+  // this can be used to flash new firmware even when serial DTS line is not connected, so no auto-reset on serial connect is performed
+  // this schematic does not use a DTS line in order not to purge unsafed data accidentially
+  // also it is normally not connected via USB directly, but over RS-232 with some metres of cable in between
+  // called from serial routine, so that a serial command, iE "reset 1000" calls this function with value given
+  // tested OK with a 1000ms delay before starting avrdude to upload the new binary
+  saveAllCurrentData(false);
+  Serial.print(F("saved all data, resetting in "));
+  Serial.print(afterms);
+  Serial.println("ms...");
+  Serial.end();
+  delay(afterms);
+  //Serial.println(F("RESETTING NOW"));
+  doHardreset();
+
+  // WDT reset DOES NOT put bootloader in flash mode!!
+  //wdt_disable();
+  //wdt_enable(WDTO_4S);
+  //while (1) {delay(500); Serial.print(".");}
+}
+
+void doHardreset() {
+  pinMode(PIN_OUT_HARDRESET, OUTPUT);
+  digitalWrite(PIN_OUT_HARDRESET, LOW); // pull a pin low that is connected to /RESET as WDT reset DOES NOT put bootloader in flash mode!!
+}

+ 590 - 0
Hardware/Firmware_Arduino_ATmega328p/DualS0ImpCounter/serialControl.ino

@@ -0,0 +1,590 @@
+void serialEvent() {
+  //bool doEval = false;
+  while (Serial.available()) {
+    char ch = Serial.read();
+    cmdBuffer[cmdBufferCount] = ch;
+
+    if ((ch == 13 || ch == 10)) { // ASCII code 13 = "CR", 10 = "LF"
+      cmdBuffer[cmdBufferCount] = 0; // nullterminator
+      //Serial.print("CR_  ");
+      //Serial.print(cmdBuffer);
+      //evalCmd();
+      if (cmdBufferCount >= 1) evalCmd();
+      else {
+        cmdBufferCount = 0;
+        for ( int i = 0; i < sizeof(cmdBuffer);  ++i ) cmdBuffer[i] = (char)0;
+      }
+    }
+    //    else if (ch == 10 && cmdBufferCount > 1) { // ASCII code 10 = "LF"
+    //      cmdBuffer[cmdBufferCount] = 0; // nullterminator
+    //      //Serial.print("LF__  ");
+    //      //Serial.print(cmdBuffer);
+    //      //evalCmd();
+    //      doEval = true;
+    //    }
+    else {
+      cmdBufferCount++;
+    }
+  }
+}
+
+
+
+void evalCmd() {
+  if (debug) {
+    Serial.print("cmd: '");
+    Serial.print(cmdBuffer);
+    Serial.println("'");
+    //Serial.println(strlen(cmdBuffer));
+  }
+
+  // begin commands
+  if (strncmp(cmdBuffer, "ID", 2) == 0 && strlen(cmdBuffer) == 2) {
+    Serial.print(PROJECT_NAME);
+    Serial.print(" v");
+    Serial.print(PROJECT_VERSION);
+    Serial.println();
+  }
+
+  else if (strncmp(cmdBuffer, "get eeprom", 10) == 0 && strlen(cmdBuffer) == 10) {
+    getEEPROMContent();
+  }
+
+  else if (strncmp(cmdBuffer, "save data", 9) == 0 && strlen(cmdBuffer) == 9) {
+    saveAllCurrentData(false);
+  }
+
+  else if (strncmp(cmdBuffer, "debug 1", 7) == 0 && strlen(cmdBuffer) == 7) {
+    debug = true;
+    debuglevel = 1;
+    byte tmpval = 1;
+    Serial.println(F("DEBUG ENABLED"));
+    EEPROM.put(eeprom_addr_debug, tmpval);
+  }
+  else if (strncmp(cmdBuffer, "debug 0", 7) == 0 && strlen(cmdBuffer) == 7) {
+    debug = false;
+    debuglevel = 0;
+    byte tmpval = 0;
+    Serial.println(F("DEBUG DISABLED"));
+    EEPROM.put(eeprom_addr_debug, tmpval);
+  }
+
+  else if (strncmp(cmdBuffer, "format all", 10) == 0 && strlen(cmdBuffer) == 10) {
+    formatEEPROM_AllData();
+  }
+
+  else if (strncmp(cmdBuffer, "format c", 8) == 0 && strlen(cmdBuffer) >= 8) {
+    if (strlen(cmdBuffer) == 8) {
+      Serial.println(F("missing counter number"));
+    }
+    else if (strlen(cmdBuffer) == 9) {
+      char _tmpcNum[2];
+      _tmpcNum[0] = cmdBuffer[8];
+      _tmpcNum[1] = '\0';
+      byte _cNum = atoi(_tmpcNum);
+      //Serial.println(_cNum);
+      if (_cNum > 0 && _cNum <= COUNTERS_COUNT) {
+        formatEEPROMAreaOfCounter(_cNum - 1);
+      }
+      else {
+        Serial.println(F("invalid counter number"));
+      }
+    }
+  }
+
+  else if (strncmp(cmdBuffer, "get readings", 12) == 0 && strlen(cmdBuffer) == 12) {
+    printCurrentReadings();
+  }
+
+  else if (strncmp(cmdBuffer, "get imp c", 9) == 0 && strlen(cmdBuffer) >= 9) {
+    if (strlen(cmdBuffer) == 9) {
+      Serial.println(F("missing counter number"));
+    }
+    else if (strlen(cmdBuffer) == 10) {
+      char _tmpcNum[2];
+      _tmpcNum[0] = cmdBuffer[9];
+      _tmpcNum[1] = '\0';
+      byte _cNum = atoi(_tmpcNum);
+      //Serial.println(_cNum);
+      if (_cNum > 0 && _cNum <= COUNTERS_COUNT) {
+        restoreLastSavedImpulseCount(_cNum - 1, true);
+      }
+      else {
+        Serial.println(F("invalid counter number"));
+      }
+    }
+  }
+
+  else if (strncmp(cmdBuffer, "get pwrgood", 11) == 0 && strlen(cmdBuffer) == 11) {
+    printPowerValue();
+  }
+
+  else if (strncmp(cmdBuffer, "set pwrgood", 11) == 0 && strlen(cmdBuffer) >= 13) {
+    uint16_t tmpvalue = 0;
+    char offset = 13;
+    char len = strlen(cmdBuffer) - offset;
+    if (strlen(cmdBuffer) >= offset) {
+      for (char i = 0; i < len; i++) {
+        if (i < (sizeof(cmdDataBuffer) - 1)) cmdDataBuffer[i] = cmdBuffer[i + offset];
+      }
+      cmdDataBuffer[len] = '\0';
+      //Serial.println();
+      //Serial.print("'");
+      //Serial.print(cmdDataBuffer);
+      //Serial.println("'");
+
+      char _value1[6];
+      uint8_t _ivalue1;
+      byte _i2 = 0;
+      for (byte i = offset; i < strlen(cmdBuffer); i++) {
+        _value1[_i2] = cmdBuffer[i];
+        _i2++;
+      }
+      _value1[_i2] = '\0';
+      _ivalue1 = atoi(_value1);
+
+      if (_ivalue1 >= 0 && _ivalue1 <= 1023) {
+        Serial.print(F("RES: set pwrGood="));
+        Serial.print(_ivalue1);
+        Serial.println();
+        powerGoodMinValue = _ivalue1;
+      }
+
+      saveGlobalConfig();
+
+    }
+  }
+
+  else if (strncmp(cmdBuffer, "set json 0", 10) == 0 && strlen(cmdBuffer) == 10) {
+    output_json = false;
+    byte tmpval = 0;
+    EEPROM.put(eeprom_addr_output_json, tmpval);
+  }
+
+  else if (strncmp(cmdBuffer, "set json 1", 10) == 0 && strlen(cmdBuffer) == 10) {
+    output_json = true;
+    byte tmpval = 1;
+    EEPROM.put(eeprom_addr_output_json, tmpval);
+  }
+
+  else if (strncmp(cmdBuffer, "get conf", 8) == 0 && strlen(cmdBuffer) >= 8) {
+    //    if (strlen(cmdBuffer) > 8 && cmdBuffer[8] == ' ' && cmdBuffer[9] == 'c') {
+    //      // is "get conf c#"
+    //      if (strlen(cmdBuffer) == 10) {
+    //        Serial.println(F("missing counter number"));
+    //      }
+    //      else {
+    //        uint16_t tmpvalue = 0;
+    //        char offset = 10;
+    //        char len = strlen(cmdBuffer) - offset;
+    //        if (strlen(cmdBuffer) >= offset) {
+    //          for (char i = 0; i < len; i++) {
+    //            if (i < (sizeof(cmdDataBuffer) - 1)) cmdDataBuffer[i] = cmdBuffer[i + offset];
+    //          }
+    //          cmdDataBuffer[len] = '\0';
+    //          //Serial.println(cmdDataBuffer);
+    //          tmpvalue = atoi(cmdDataBuffer);
+    //          if (tmpvalue > 0 && tmpvalue <= COUNTERS_COUNT) {
+    //            //Serial.print("conf counter ");
+    //            //Serial.println(tmpvalue);
+    //            printCounterConf(tmpvalue - 1);
+    //          }
+    //          else {
+    //            Serial.println(F("counter number invalid"));
+    //          }
+    //
+    //        }
+    //      }
+    //    }
+    //    else {
+    // // is "get conf" - so show all
+    printGlobalConf();
+    for (byte i = 0; i < COUNTERS_COUNT; i++) {
+      printCounterConf(i);
+    }
+    //    }
+  }
+
+  else if (strncmp(cmdBuffer, "set debounce", 12) == 0 && strlen(cmdBuffer) >= 14) {
+    uint16_t tmpvalue = 0;
+    char offset = 13;
+    char len = strlen(cmdBuffer) - offset;
+    if (strlen(cmdBuffer) >= offset) {
+      for (char i = 0; i < len; i++) {
+        if (i < (sizeof(cmdDataBuffer) - 1)) cmdDataBuffer[i] = cmdBuffer[i + offset];
+      }
+      cmdDataBuffer[len] = '\0';
+      //Serial.println();
+      //Serial.print("'");
+      //Serial.print(cmdDataBuffer);
+      //Serial.println("'");
+
+      char _value1[6];
+      char _value2[6];
+      uint8_t _ivalue1, _ivalue2;
+      bool _withValue2;
+      byte _sepOffset = 0;
+      byte _i2 = 0;
+      for (byte i = offset; i < strlen(cmdBuffer); i++) {
+        if (cmdBuffer[i] == ',') {
+          //Serial.print("found , at offset ");
+          //Serial.println(i);
+          _sepOffset = i;
+        }
+        else if (_sepOffset == 0) {
+          _value1[_i2] = cmdBuffer[i];
+          _i2++;
+        }
+      }
+      _value1[_i2] = '\0';
+
+      if (_sepOffset > 0) {
+        _i2 = 0;
+        for (byte i = _sepOffset + 1; i < strlen(cmdBuffer); i++) {
+          _value2[_i2] = cmdBuffer[i];
+          _i2++;
+        }
+        _value2[_i2] = '\0';
+        _withValue2 = true;
+      }
+      else {
+        _value2[0] = '\0'; // no _value2 was given
+        _withValue2 = false;
+      }
+
+      _ivalue1 = atoi(_value1);
+      _ivalue2 = atoi(_value2);
+
+      if (_ivalue1 >= 0 && _ivalue1 <= 200) {
+        Serial.print(F("RES: set debounce="));
+        Serial.print(_ivalue1);
+        debounceDelay = _ivalue1;
+      }
+
+      if (_withValue2 && _ivalue2 >= 0 && _ivalue2 <= 500) {
+        Serial.print(F(", debounceRecov="));
+        Serial.print(_ivalue2);
+        debounceRecoveryDelay = _ivalue2;
+      }
+      Serial.println();
+
+      saveGlobalConfig();
+
+    }
+  }
+
+  else if (strncmp(cmdBuffer, "get debounce", 12) == 0 && strlen(cmdBuffer) == 12) {
+    Serial.print(F("debounce: "));
+    Serial.print(debounceDelay);
+    Serial.print(", ");
+    Serial.println(debounceRecoveryDelay);
+  }
+
+  else if (strncmp(cmdBuffer, "set conf c", 10) == 0 && strlen(cmdBuffer) >= 10) {
+    if (strlen(cmdBuffer) == 10) {
+      Serial.println(F("missing counter number"));
+    }
+    else if (strlen(cmdBuffer) >= 15) {
+      uint16_t tmpvalue = 0;
+      char offset = 10;
+      char len = strlen(cmdBuffer) - offset;
+      if (strlen(cmdBuffer) >= offset) {
+        char _cNumBuf[2];
+        char _commandBuffer[11];
+        char _valueBuffer[11];
+        //byte _delimitersFound = 0;
+        byte _cNum;
+        boolean _cNumOK = false;
+        //
+        for (byte i = 0; i < len; i++) {
+          if (i < (sizeof(cmdDataBuffer) - 1)) cmdDataBuffer[i] = cmdBuffer[i + offset];
+        }
+        cmdDataBuffer[len] = '\0';
+        Serial.print("cmdDataBuffer: '");
+        Serial.print(cmdDataBuffer);
+        Serial.println("'");
+
+        // get counter number, expect it on 1st place and 1 char long
+        _cNumBuf[0] = cmdDataBuffer[0];
+        _cNumBuf[1] = '\0';
+        _cNum = atoi(_cNumBuf);
+
+        if (_cNum > 0 && _cNum <= COUNTERS_COUNT) {
+          Serial.print("_cNum=");
+          Serial.println(_cNum);
+          _cNumOK = true;
+        }
+        else if (cmdDataBuffer[1] != ' ') {
+          Serial.println(F("ERROR - invalid syntax"));
+        }
+        else {
+          Serial.print("_cNum invalid: ");
+          Serial.println(_cNum);
+        }
+
+        //        Serial.println();
+        //        Serial.print("cmdDataBuffer[1]='");
+        //        Serial.print(cmdDataBuffer[1]);
+        //        Serial.println("'");
+
+
+        if (_cNumOK && strlen(cmdDataBuffer) > 4) {
+          // https://arduino.stackexchange.com/questions/1013/how-do-i-split-an-incoming-string
+          // Read each command pair
+          char* _param = strtok(cmdDataBuffer, " ");
+          while (_param != 0)
+          {
+            // Split the command in two values
+            char* _value = strchr(_param, '=');
+            if (_value != 0)
+            {
+              // Actually split the string in 2: replace ':' with 0
+              *_value = 0;
+              strlwr(_param);
+
+              //              Serial.print("_param='");
+              //              Serial.print(_param);
+
+              ++_value;
+
+              //              Serial.print("'   ");
+              //              Serial.print("_value='");
+              //              Serial.print(_value);
+              //              Serial.println("'");
+
+              if (strcmp(_param, "impperunit") == 0) {
+                Serial.print("impPerUnit=");
+                Serial.println(atoi(_value));
+                meter_impPerUnit[_cNum - 1] = atoi(_value);
+              }
+              else if (strcmp(_param, "noimptout") == 0) {
+                Serial.print("noImpTout=");
+                Serial.println(atoi(_value));
+                meter_noImpulseTimeout_seconds[_cNum - 1] = atoi(_value);
+              }
+              else if (strcmp(_param, "saveint") == 0) {
+                Serial.print("saveInt=");
+                Serial.println(atoi(_value));
+                meter_savePulsesOnInterval_mins[_cNum - 1] = atoi(_value);
+              }
+              else {
+                Serial.print(F("unknown parameter '"));
+                Serial.print(_param);
+                Serial.println("'");
+              }
+
+              printCounterConf(_cNum - 1);
+
+            }
+            // Find the next command in input string
+            _param = strtok(0, ";");
+          }
+        }
+        else {
+          Serial.println(F("invalid command"));
+        }
+      }
+    }
+  }
+
+  else if (strncmp(cmdBuffer, "save conf", 9) == 0 && strlen(cmdBuffer) == 9) {
+    Serial.println(F("SAVING CONFIG"));
+    saveCountersConfig();
+    saveGlobalConfig();
+  }
+
+#ifdef INCLUDE_TESTFUNCTIONS
+  else if (strncmp(cmdBuffer, "test init c2", 12) == 0 && strlen(cmdBuffer) == 12) {
+    Serial.println("test init c2");
+    
+    formatEEPROMAreaOfCounter(1);
+    
+    eeprom_writecounter_currentReadingImpulses[1] = 65530;
+    eeprom_nextoffset_currentReadingImpulses[1] = 0;
+  }
+  
+  else if (strncmp(cmdBuffer, "test c2", 7) == 0 && strlen(cmdBuffer) == 7) {
+    increaseCounter(1);
+    storeCurrentImpulses(1, false);
+  }
+#endif
+
+  else if (strncmp(cmdBuffer, "set reading", 11) == 0 && strlen(cmdBuffer) >= 11) {
+    uint16_t tmpvalue = 0;
+    char tmpdata_1[10];
+    char tmpdata_2[10];
+    unsigned long newReading;
+    uint16_t newImpulses;
+
+    if (strlen(cmdBuffer) <= 13) {
+      Serial.println(F("ERROR: missing valid counter number"));
+    }
+    else if ( strlen(cmdBuffer) > 13 && cmdBuffer[11] == ' ' && cmdBuffer[12] == 'c') {
+      byte _cNum;
+
+      char tmp_cNum[2];
+      tmp_cNum[0] = cmdBuffer[13];  // atoi needs char array to work...
+      tmp_cNum[1] = 0;
+      _cNum = atoi(tmp_cNum);
+
+      if (_cNum < 1 || _cNum > COUNTERS_COUNT) {
+        Serial.println(F("ERROR: invalid counter number"));
+      }
+      else if (_cNum > 0 && _cNum <= COUNTERS_COUNT) {
+        Serial.print(F("got valid counter number: "));
+        Serial.println(_cNum);
+
+        _cNum = _cNum - 1; // we actually need the array index, not the pretty number...
+
+        //char offset = 12;
+        byte offset = 15;
+        byte len = strlen(cmdBuffer) - offset;
+        Serial.println("SET READING");
+
+        if (strlen(cmdBuffer) > offset) {
+          //for (char i = 0; i < len; i++) {
+          //  if (i < (sizeof(cmdDataBuffer) - 1)) cmdDataBuffer[i] = cmdBuffer[i + offset];
+          //}
+          bool value_1_finished = false;
+          bool value_2_finished = false;
+          bool commaGiven = false;
+          bool impulsesGiven = false;
+          uint8_t i1 = 0;
+          uint8_t i2 = 0;
+          //Serial.println("vor val1");
+          while (!value_1_finished) {
+            if (isdigit(cmdBuffer[i1 + offset])) {
+              if (i1 < (sizeof(tmpdata_1) - 1)) tmpdata_1[i1] = cmdBuffer[i1 + offset];
+              //Serial.print("  ");
+              //Serial.print(i1);
+              i1++;
+              i2++;
+            }
+            else if (cmdBuffer[i1 + offset] == '.' || cmdBuffer[i1 + offset] == ',' || cmdBuffer[i1 + offset] == ' ') {
+              value_1_finished = true;
+              if (cmdBuffer[i1 + offset] == '.' || cmdBuffer[i1 + offset] == ',') commaGiven = true;
+              //Serial.println("value_1_finished=true");
+              i1++;
+            }
+            else if (cmdBuffer[i1 + offset] == '\0') {
+              //Serial.println("value_[1|2]_finished=true");
+              value_1_finished = true;
+              value_2_finished = true; // end of string reached - no value 2 was given
+            }
+          }
+          tmpdata_1[i2] = '\0';
+          newReading = atol(tmpdata_1);
+          //Serial.print(F("value 1: "));
+          //Serial.println(tmpdata_1);
+
+
+          if (!value_2_finished) {
+            impulsesGiven = true;
+            i2 = 0;
+            while (!value_2_finished) {
+              if (isdigit(cmdBuffer[i1 + offset])) {
+                if (i2 < (sizeof(tmpdata_2) - 1)) tmpdata_2[i2] = cmdBuffer[i1 + offset];
+                i1++;
+                i2++;
+              }
+              else if (cmdBuffer[i1 + offset] == ' ' || cmdBuffer[i1 + offset] == '\0') {
+                value_2_finished = true; // end of string reached
+              }
+            }
+            tmpdata_2[i2] = '\0';
+            newImpulses = atoi(tmpdata_2);
+            //Serial.print(F("value 2: "));
+            //Serial.println(tmpdata_2);
+          }
+
+          if (commaGiven && impulsesGiven && tmpdata_2 >= 0) {
+            if ((meter_impPerUnit[_cNum] == 10 && newImpulses < 10) || (meter_impPerUnit[_cNum] == 100 && newImpulses < 100) || (meter_impPerUnit[_cNum] == 1000 && newImpulses < 1000) || (meter_impPerUnit[_cNum] == 10000 && newImpulses < 10000)) {
+              Serial.print(F("INFO: set new reading: "));
+              Serial.print(newReading);
+              Serial.print(".");
+
+              if (meter_impPerUnit[_cNum] == 100 && newImpulses < 10) Serial.print("0");
+              else if (meter_impPerUnit[_cNum] == 1000 && newImpulses < 10) Serial.print("00");
+              else if (meter_impPerUnit[_cNum] == 1000 && newImpulses < 100) Serial.print("0");
+              Serial.println(newImpulses);
+
+              currentReading[_cNum] = newReading;
+              currentReadingImpulses[_cNum] = newImpulses;
+              formatEEPROMAreaOfCounter(_cNum);
+              storeCurrentReading(_cNum, true);
+              storeCurrentImpulses(_cNum, true);
+            }
+            else {
+              Serial.print(F("ERROR: invalid decimals for set impPerUnit="));
+              Serial.print(meter_impPerUnit[_cNum]);
+              Serial.println(" !!!");
+            }
+          }
+          else if (!commaGiven && impulsesGiven) {
+            Serial.print(F("INFO: set new reading: "));
+            Serial.println(newReading);
+            Serial.print(F("INFO: set new impulses: "));
+            Serial.println(newImpulses);
+            currentReading[_cNum] = newReading;
+            currentReadingImpulses[_cNum] = newImpulses;
+            formatEEPROMAreaOfCounter(_cNum);
+            storeCurrentReading(_cNum, true);
+            storeCurrentImpulses(_cNum, true);
+          }
+          else if (!commaGiven && !impulsesGiven) {
+            Serial.print(F("INFO: set new reading: "));
+            Serial.println(newReading);
+            currentReading[_cNum] = newReading;
+            currentReadingImpulses[_cNum] = 0;
+            formatEEPROMAreaOfCounter(_cNum);
+            storeCurrentReading(_cNum, true);
+            storeCurrentImpulses(_cNum, true);
+          }
+        }
+      }
+    }
+  }
+
+  else if (strncmp(cmdBuffer, "get wcount", 10) == 0 && strlen(cmdBuffer) == 10) {
+    for (int i = 0; i < COUNTERS_COUNT; i++) {
+      Serial.print(F("wCount C"));
+      Serial.print(i + 1);
+      Serial.print("=");
+      Serial.println(eeprom_writecounter_currentReadingImpulses[i]);
+    }
+  }
+
+  else if (strncmp(cmdBuffer, "reset", 5) == 0 && strlen(cmdBuffer) >= 5) {
+    if (strlen(cmdBuffer) == 5) {
+      resetForFlashing(0);
+    }
+    else {
+      uint16_t tmpvalue = 0;
+      char offset = 6;
+      char len = strlen(cmdBuffer) - offset;
+      if (strlen(cmdBuffer) >= offset) {
+        for (char i = 0; i < len; i++) {
+          if (i < (sizeof(cmdDataBuffer) - 1)) cmdDataBuffer[i] = cmdBuffer[i + offset];
+        }
+        cmdDataBuffer[len] = '\0';
+        Serial.println(cmdDataBuffer);
+        tmpvalue = atoi(cmdDataBuffer);
+        if (tmpvalue >= 0 && tmpvalue <= 15000) {
+          resetForFlashing(tmpvalue);
+        }
+        else Serial.println(F("out of range 0-15000"));
+      }
+    }
+  }
+
+  else {
+    Serial.print(F("UNKNOWN COMMAND: '"));
+    Serial.print(cmdBuffer);
+    Serial.println("'");
+  }
+
+
+
+  cmdBufferCount = 0;
+  for ( int i = 0; i < sizeof(cmdBuffer);  ++i ) cmdBuffer[i] = (char)0;
+}

+ 201 - 0
Hardware/README.md

@@ -0,0 +1,201 @@
+# DualS0ImpCounter
+
+Arduino based hardware for capturing impulses from S0 impulse meters. 
+
+The main reason for starting this project was, that counting S0 impulses directly with the Raspberry Pi GPIOs has proven me to be unreliable. I did this for a longer time and got intermittent impulses recorded regularly, so that the counters on the actual meters differed from the recorded values more and more over time. At least I made this experience using RasPi GPIO and a python program for reading them. 
+On the other hand, on every downtime of the Raspberry, there are no data recorded at all, so that - again - the actual counters differ with the records with time. 
+
+### Software
+
+compiled using Arduino 1.8
+
+- 2 independent configurable S0 inputs/counters
+
+- direct implementation of UNITS- and IMPULSES- (between full unit) counters, so that the device can keep track of the actual meters for a long time without the need of an up and running host system, as long as there is electric power available. 
+  This was the main reason for me to start this project. 
+
+- configurable impulses per unit and unit counter per input (currently supports 10/100/1000 imp/unit)
+
+- store current unit readings to EEPROM on every change
+
+  - EEPROM endurance should not be a problem in most cases here. 
+    EEPROM has guaranteed 100.000 write cycles per cell: 
+    - i.E. electric energy meter counting 5000 kWh p.A. => EEPROM lasts 20 years
+    - gas meter, 500-1000 m³ p.A. => EEPROM lasts 100 years
+  - a unit rollover means i.E. every 10/100/1000 impulses, so this value is not written that often
+  - protection against write failures - every value is written 3 times on different EEPROM addresses, therefore it is possible to restore a valid value even if there is a data inconsistency
+
+- store impulses between units to EEPROM in configurable intervals
+
+  - EEPROM endurance
+
+    - as these values are written far more often we need some kind of wear leveling here
+
+    - implemented as ring buffer which stores the value and a write counter, every time to another EEPROM cell, until the reserved memory area is full, then starts again at the beginning. 
+
+      EEPROM area is currently hard coded and set to: 
+
+      - counter 1: 512 bytes or 128 values
+
+      - counter 2: 128 bytes or 32 values
+
+        one dataset is 2 bytes data + 2 bytes write counter
+
+    - protection against write failures: write counter is written _after_ the data, on restore a valid write counter must be exactly 1 value bigger than the one before, so in every case a not too old value should be restorable
+
+    - save on no-impulse-timeout (i.E. for gas counters which count several impulses and then be idle for a longer time when the heating has been switched off by the thermostat)
+
+    - save on fixed interval
+
+- store all current unsaved data on power loss, implemented using: 
+
+  - capacitor buffered power supply with relatively high voltage
+  - power loss detection using an ADC input
+
+- measuring of duration in between impulses (which can then be used to calculate power/momentary usage)
+
+- data output via UART on every impulse and on no-impulse/fixed timeout
+
+- configuration via UART commands
+
+- intended to be used aside a Raspberry Pi or similar, logging data to an InfluxDB server with python program [s0meters.py](../s0meters_py)
+
+- software function to trigger MCU reset (via GPIO output connected to /RES input) in order to be able to update/flash the MCU without on-site intervention although the normal Arduino flash/reset method doesn´t work by design. This output is normally configured as input and has a pullup resistor (on the Pro Mini board), so that it does not prevent from normal flashing using a USB-UART Arduino interface. 
+  Of course this function saves all data to EEPROM before actually resetting the MCU. 
+
+- WDT enabled, this possibly requires flashing another boot loader depending on the Arduino board used (Pro Minis usually come with a different boot loader than Unos, which does not support WDT - Optiboot works well - I use a custom Optiboot version with baud rate 57600 as is the default for early Pro Mini boards)
+
+
+
+### Hardware
+
+Schematics (KiCad) here: [schematics](schematics/) 
+I also created a PCB layout, despite I only built a prototype on breadboard, as it speeds up this process by far. It can be found in schematics folder. 
+
+- based on Arduino Pro Mini (or clone, with ATmega 328p MCU)
+- power supply using a 12VDC wall plug
+- big buffer capacitor only for the MCU itself, right before it´s diode decoupled 5VDC regulator, 
+- resistor network from 12VDC supply to ADC input to detect power loss early enough
+- 2 S0 impulse inputs using optocouplers, active LOW (compatible with S0 outputs, which are usually open collector outputs)
+- connection to host over RS232, so **NOT USING USB POWER SUPPLY**
+- RS232 connection **without DTS signal**, so that the MCU cannot be surprise-reset by the host on (re-)connect
+- reset circuit (connection from a GPIO out to /RES input)
+
+
+
+### UART output
+
+If configuration JSON = 1 (default), the module outputs a JSON formatted dataset on UART on every incoming impulse and on no-impulse-timeout: 
+
+```
+{"C":CNUM,"reading":READING,"dTime":DTIME}
+```
+
+where:
+
+- CNUM = 1, 2...
+- READING= actual current reading with decimals, i.E. 1234.123
+- DTIME= time in ms since the last impulse (not present if requested by command '_get readings_', = 0 if sent on no-impulse-timeout)
+
+
+
+### UART commands
+
+default UART baud rate: 57600, 8 data bits, no parity, 1 stop bit
+
+#### Impulse inputs configuration
+
+configure impulse counter inputs: 
+
+```
+set conf c1 impPerUnit=1000
+set conf c1 noImpTout=60
+set conf c1 saveInt=15
+```
+
+or as a batch job:
+
+```
+set conf c1 impPerUnit=1000;noImpTout=60;saveInt=15
+set conf c2 impPerUnit=100;noImpTout=60;saveIint=15
+```
+
+where:
+
+- noImpTout in seconds
+- saveInt in minutes
+
+- c1/c2 is the input/counter number
+
+
+
+#### Set counter readings
+
+used for initial setting and value corrections
+
+```
+set reading cN UNITCOUNTER[.IMPULSES]
+
+i.E.:
+set reading c1 1023.423
+```
+
+where:
+
+- cN: counter number (c1, c2...)
+- UNITCOUNTER: counter in the main unit (digits before comma)
+- IMPULSES: optional, impulses since last unit counter rollover (or comma places on the actual meter)
+
+- if a valid value is given, EEPROM area belonging to counter number is formatted and new value stored instantly
+
+
+
+#### Set power-good
+
+Sets ADC value for "power good".
+POWER GOOD - monitors voltage in front of the onboard voltage regulator powering the AVR/Arduino
+in order to save all data to EEPROM before power is really gone. 
+To make this possible, supply voltage is much higher than needed for an AVR/Arduino (9-12V) connected to 
+a big (2200uF) capacitor over a decoupling diode (voltage drop 0.6-0.7V) and regulated to Vcc=5V 
+by the Arduino onboard regulator. 
+Vin is measured through a voltage divider of 56k/24k (after the diode).
+A value of 420 seems to be the minimum at ~7.5V supply voltage (in front of the decoupling diode). 
+Below this the ADC value increases again due to voltage regulator drop out and therefore sinking Vref, 
+so a reasonable safety margin is mandatory here. As we use a 12V supply we set this to 500 for now (which is about ~= 9.0V)
+
+First check current ADC value using: 
+
+```
+get pwrgood
+```
+
+Then set new value with a safety margin - do not use a too low value! 
+
+```
+set pwrgood 500
+```
+
+
+
+#### commands overview
+
+| command                     | description                                                  |
+| --------------------------- | ------------------------------------------------------------ |
+| get eeprom                  | print entire EEPROM content to UART (formatted)              |
+| save data                   | save all unsaved current data                                |
+| debug [1\|0]                | switch on/off debug output                                   |
+| format [all\|c1\|c2]        | format EEPROM area (all, or only counter1/2)                 |
+| get readings                | print current readings to UART as done on every impulse      |
+| get imp cN                  | get current impulses count of counter N                      |
+| get pwrgood                 | print current power supply ADC value and configured "power good" value |
+| set pwrgood VALUE           | set "power good" to an ADC value. <br />If power supply falls below this value, all data will be saved to EEPROM once <br />and further saving will be stopped until power is "good" again. |
+| set json 0\|1               | enable/disable readings output in JSON format (1=default)    |
+| get conf                    | print current counters configuration to UART                 |
+| get debounce                | print current input debounce values (in ms)                  |
+| set debounce VALUE[,VALUE2] | set input debounce<br />VALUE = debounce time in ms<br />VALUE2 = debounce recovery time in ms (optional, comma separated) |
+| set conf cN                 | counter configuration for counter N, as described above      |
+| save conf                   | to be called after all configuration changes to store them to EEPROM |
+| set reading cN              | sets the current reading of counter N to value given as described above<br />comma separator is '.' |
+| get wcount                  | print write counters of all counters                         |
+| reset DELAY                 | resets the MCU via GPIO output connected to /RESET input<br />used for firmware flashing. <br />[delay] is optional, can be used to fine tune successful flashing with avrdude. |
+

+ 164 - 0
Hardware/Schematics/FloKra_Modules.pretty/ArduinoProMini_V2wCrystal_allHeaders.kicad_mod

@@ -0,0 +1,164 @@
+(module ArduinoProMini_V2wCrystal_allHeaders (layer F.Cu) (tedit 5F9182D6)
+  (descr "IC, ARDUINO_PRO_MINI x 0,6\"")
+  (tags "DIL ARDUINO PRO MINI")
+  (fp_text reference Module1 (at -13.97 10.16) (layer F.SilkS)
+    (effects (font (size 0.8 0.8) (thickness 0.16)))
+  )
+  (fp_text value ArduinoProMini_v2wCrystal_allHeaders (at 0 0) (layer F.Fab) hide
+    (effects (font (size 0.8 0.8) (thickness 0.16)))
+  )
+  (fp_line (start -17.526 -8.89) (end 15.24 -8.89) (layer F.SilkS) (width 0.15))
+  (fp_line (start 15.24 9.144) (end -17.526 9.144) (layer F.SilkS) (width 0.15))
+  (fp_line (start -17.526 -8.89) (end -17.526 9.144) (layer F.SilkS) (width 0.15))
+  (fp_line (start 15.24 9.144) (end 15.24 -8.89) (layer F.SilkS) (width 0.15))
+  (pad 24 thru_hole oval (at -13.97 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 23 thru_hole oval (at -11.43 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 22 thru_hole oval (at -8.89 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 21 thru_hole oval (at -6.35 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 20 thru_hole oval (at -3.81 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 19 thru_hole oval (at -1.27 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 18 thru_hole oval (at 1.27 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 17 thru_hole oval (at 3.81 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 16 thru_hole oval (at 6.35 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 15 thru_hole oval (at 8.89 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 14 thru_hole oval (at 11.43 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 13 thru_hole oval (at 13.97 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 12 thru_hole oval (at 13.97 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 11 thru_hole oval (at 11.43 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 10 thru_hole oval (at 8.89 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 9 thru_hole oval (at 6.35 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 8 thru_hole oval (at 3.81 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 7 thru_hole oval (at 1.27 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 6 thru_hole oval (at -1.27 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 5 thru_hole oval (at -3.81 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 4 thru_hole oval (at -6.35 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 3 thru_hole oval (at -8.89 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 2 thru_hole oval (at -11.43 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 1 thru_hole oval (at -13.97 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 30 thru_hole oval (at -16.51 6.35 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 1 thru_hole oval (at -16.51 3.81 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 2 thru_hole oval (at -16.51 1.27 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 2 thru_hole oval (at -16.51 -1.27 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 2 thru_hole oval (at -16.51 -3.81 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 2 thru_hole oval (at -16.51 -6.35 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 4 thru_hole oval (at 13.97 5.08 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 25 thru_hole oval (at 13.97 2.54 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 26 thru_hole oval (at 13.97 0 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 27 thru_hole oval (at 13.97 -2.54 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 28 thru_hole oval (at 13.97 -5.08 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (model Socket_Strips.3dshapes/Socket_Strip_Straight_1x02_Pitch2.54mm.wrl
+    (offset (xyz -3.809999942779541 5.079999923706055 0))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model Socket_Strips.3dshapes/Socket_Strip_Straight_1x03_Pitch2.54mm.wrl
+    (offset (xyz 13.96999979019165 2.539999961853027 0))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 90))
+  )
+  (model Socket_Strips.3dshapes/Socket_Strip_Straight_1x12_Pitch2.54mm.wrl
+    (offset (xyz 0 7.619999885559082 0))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model Socket_Strips.3dshapes/Socket_Strip_Straight_1x12_Pitch2.54mm.wrl
+    (offset (xyz 0 -7.619999885559082 0))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model Socket_Strips.3dshapes/Socket_Strip_Straight_1x02_Pitch2.54mm.wrl
+    (offset (xyz 6.349999904632568 5.079999923706055 0))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model ${MYSLOCAL}/mysensors.3dshapes/mysensors_arduino.3dshapes/arduino_pro_mini.wrl
+    (offset (xyz -1.269999980926514 0 12.19199981689453))
+    (scale (xyz 0.395 0.395 0.395))
+    (rotate (xyz 0 0 180))
+  )
+  (model SMD_Packages.3dshapes/TQFP-32.wrl
+    (offset (xyz 1.269999980926514 0 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 315))
+  )
+  (model Pin_Headers.3dshapes/Pin_Header_Straight_1x12_Pitch2.54mm.wrl
+    (offset (xyz 13.96999979019165 -7.619999885559082 11.30299983024597))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 180 90))
+  )
+  (model Pin_Headers.3dshapes/Pin_Header_Straight_1x12_Pitch2.54mm.wrl
+    (offset (xyz 13.96999979019165 7.619999885559082 11.30299983024597))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 180 90))
+  )
+  (model Pin_Headers.3dshapes/Pin_Header_Straight_1x03_Pitch2.54mm.wrl
+    (offset (xyz 13.96999979019165 5.079999923706055 11.30299983024597))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 180 0))
+  )
+  (model Pin_Headers.3dshapes/Pin_Header_Straight_1x02_Pitch2.54mm.wrl
+    (offset (xyz 7.619999885559082 5.079999923706055 11.30299983024597))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 180 90))
+  )
+  (model Pin_Headers.3dshapes/Pin_Header_Straight_1x02_Pitch2.54mm.wrl
+    (offset (xyz -2.539999961853027 5.079999923706055 11.30299983024597))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 180 90))
+  )
+  (model ${MYSLOCAL}/mysensors.3dshapes/w.lain.3dshapes/smd_leds/led_0603.wrl
+    (offset (xyz -7.619999885559082 0 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model ${MYSLOCAL}/mysensors.3dshapes/w.lain.3dshapes/smd_leds/led_0603.wrl
+    (offset (xyz 13.96999979019165 -4.444999933242798 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model Pin_Headers.3dshapes/Pin_Header_Angled_1x06_Pitch2.54mm.wrl
+    (offset (xyz -16.50999975204468 -6.349999904632568 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 180))
+  )
+  (model Resistors_SMD.3dshapes/R_0603.wrl
+    (offset (xyz -7.619999885559082 -1.269999980926514 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model Resistors_SMD.3dshapes/R_0603.wrl
+    (offset (xyz 13.96999979019165 -3.174999952316284 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model Capacitors_SMD.3dshapes/C_0603.wrl
+    (offset (xyz -7.619999885559082 1.269999980926514 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model Capacitors_Tantalum_SMD.3dshapes/CP_Tantalum_Case-S_EIA-3216-12.wrl
+    (offset (xyz -8.889999866485596 3.809999942779541 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model Capacitors_Tantalum_SMD.3dshapes/CP_Tantalum_Case-S_EIA-3216-12.wrl
+    (offset (xyz -8.889999866485596 -3.809999942779541 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model TO_SOT_Packages_SMD.3dshapes/SOT-23-5.wrl
+    (offset (xyz -10.15999984741211 0 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 90))
+  )
+  (model Capacitors_SMD.3dshapes/C_1210.wrl
+    (offset (xyz -12.69999980926514 0 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 90))
+  )
+  (model ${MYSLOCAL}/mysensors.3dshapes/w.lain.3dshapes/switch/smd_push.wrl
+    (offset (xyz 10.15999984741211 0 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 90))
+  )
+)

+ 153 - 0
Hardware/Schematics/FloKra_Modules.pretty/ArduinoProMini_noAdditionalHeaders.kicad_mod

@@ -0,0 +1,153 @@
+(module ArduinoProMini_noAdditionalHeaders (layer F.Cu) (tedit 5F9179BE)
+  (descr "IC, ARDUINO_PRO_MINI x 0,6\"")
+  (tags "DIL ARDUINO PRO MINI")
+  (fp_text reference Module1 (at -13.97 10.16) (layer F.SilkS)
+    (effects (font (size 0.8 0.8) (thickness 0.16)))
+  )
+  (fp_text value ArduinoProMini (at 0 0) (layer F.Fab) hide
+    (effects (font (size 0.8 0.8) (thickness 0.16)))
+  )
+  (fp_line (start 15.24 9.144) (end 15.24 -8.89) (layer F.SilkS) (width 0.15))
+  (fp_line (start -17.526 -8.89) (end -17.526 9.144) (layer F.SilkS) (width 0.15))
+  (fp_line (start 15.24 9.144) (end -17.526 9.144) (layer F.SilkS) (width 0.15))
+  (fp_line (start -17.526 -8.89) (end 15.24 -8.89) (layer F.SilkS) (width 0.15))
+  (pad 1 thru_hole oval (at -13.97 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 2 thru_hole oval (at -11.43 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 3 thru_hole oval (at -8.89 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 4 thru_hole oval (at -6.35 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 5 thru_hole oval (at -3.81 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 6 thru_hole oval (at -1.27 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 7 thru_hole oval (at 1.27 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 8 thru_hole oval (at 3.81 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 9 thru_hole oval (at 6.35 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 10 thru_hole oval (at 8.89 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 11 thru_hole oval (at 11.43 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 12 thru_hole oval (at 13.97 7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 13 thru_hole oval (at 13.97 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 14 thru_hole oval (at 11.43 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 15 thru_hole oval (at 8.89 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 16 thru_hole oval (at 6.35 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 17 thru_hole oval (at 3.81 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 18 thru_hole oval (at 1.27 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 19 thru_hole oval (at -1.27 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 20 thru_hole oval (at -3.81 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 21 thru_hole oval (at -6.35 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 22 thru_hole oval (at -8.89 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 23 thru_hole oval (at -11.43 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (pad 24 thru_hole oval (at -13.97 -7.62) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS))
+  (model Socket_Strips.3dshapes/Socket_Strip_Straight_1x02_Pitch2.54mm.wrl
+    (offset (xyz -3.809999942779541 5.079999923706055 0))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model Socket_Strips.3dshapes/Socket_Strip_Straight_1x03_Pitch2.54mm.wrl
+    (offset (xyz 13.96999979019165 2.539999961853027 0))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 90))
+  )
+  (model Socket_Strips.3dshapes/Socket_Strip_Straight_1x12_Pitch2.54mm.wrl
+    (offset (xyz 0 7.619999885559082 0))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model Socket_Strips.3dshapes/Socket_Strip_Straight_1x12_Pitch2.54mm.wrl
+    (offset (xyz 0 -7.619999885559082 0))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model Socket_Strips.3dshapes/Socket_Strip_Straight_1x02_Pitch2.54mm.wrl
+    (offset (xyz 6.349999904632568 5.079999923706055 0))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model ${MYSLOCAL}/mysensors.3dshapes/mysensors_arduino.3dshapes/arduino_pro_mini.wrl
+    (offset (xyz -1.269999980926514 0 12.19199981689453))
+    (scale (xyz 0.395 0.395 0.395))
+    (rotate (xyz 0 0 180))
+  )
+  (model SMD_Packages.3dshapes/TQFP-32.wrl
+    (offset (xyz 1.269999980926514 0 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 315))
+  )
+  (model Pin_Headers.3dshapes/Pin_Header_Straight_1x12_Pitch2.54mm.wrl
+    (offset (xyz 13.96999979019165 -7.619999885559082 11.30299983024597))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 180 90))
+  )
+  (model Pin_Headers.3dshapes/Pin_Header_Straight_1x12_Pitch2.54mm.wrl
+    (offset (xyz 13.96999979019165 7.619999885559082 11.30299983024597))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 180 90))
+  )
+  (model Pin_Headers.3dshapes/Pin_Header_Straight_1x03_Pitch2.54mm.wrl
+    (offset (xyz 13.96999979019165 5.079999923706055 11.30299983024597))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 180 0))
+  )
+  (model Pin_Headers.3dshapes/Pin_Header_Straight_1x02_Pitch2.54mm.wrl
+    (offset (xyz 7.619999885559082 5.079999923706055 11.30299983024597))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 180 90))
+  )
+  (model Pin_Headers.3dshapes/Pin_Header_Straight_1x02_Pitch2.54mm.wrl
+    (offset (xyz -2.539999961853027 5.079999923706055 11.30299983024597))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 180 90))
+  )
+  (model ${MYSLOCAL}/mysensors.3dshapes/w.lain.3dshapes/smd_leds/led_0603.wrl
+    (offset (xyz -7.619999885559082 0 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model ${MYSLOCAL}/mysensors.3dshapes/w.lain.3dshapes/smd_leds/led_0603.wrl
+    (offset (xyz 13.96999979019165 -4.444999933242798 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model Pin_Headers.3dshapes/Pin_Header_Angled_1x06_Pitch2.54mm.wrl
+    (offset (xyz -16.50999975204468 -6.349999904632568 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 180))
+  )
+  (model Resistors_SMD.3dshapes/R_0603.wrl
+    (offset (xyz -7.619999885559082 -1.269999980926514 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model Resistors_SMD.3dshapes/R_0603.wrl
+    (offset (xyz 13.96999979019165 -3.174999952316284 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model Capacitors_SMD.3dshapes/C_0603.wrl
+    (offset (xyz -7.619999885559082 1.269999980926514 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model Capacitors_Tantalum_SMD.3dshapes/CP_Tantalum_Case-S_EIA-3216-12.wrl
+    (offset (xyz -8.889999866485596 3.809999942779541 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model Capacitors_Tantalum_SMD.3dshapes/CP_Tantalum_Case-S_EIA-3216-12.wrl
+    (offset (xyz -8.889999866485596 -3.809999942779541 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 0))
+  )
+  (model TO_SOT_Packages_SMD.3dshapes/SOT-23-5.wrl
+    (offset (xyz -10.15999984741211 0 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 90))
+  )
+  (model Capacitors_SMD.3dshapes/C_1210.wrl
+    (offset (xyz -12.69999980926514 0 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 90))
+  )
+  (model ${MYSLOCAL}/mysensors.3dshapes/w.lain.3dshapes/switch/smd_push.wrl
+    (offset (xyz 10.15999984741211 0 13.01749980449676))
+    (scale (xyz 1 1 1))
+    (rotate (xyz 0 0 90))
+  )
+)

+ 254 - 0
Hardware/Schematics/ImpCounter-cache.lib

@@ -0,0 +1,254 @@
+EESchema-LIBRARY Version 2.4
+#encoding utf-8
+#
+# Connector_Screw_Terminal_01x02
+#
+DEF Connector_Screw_Terminal_01x02 J 0 40 Y N 1 F N
+F0 "J" 0 100 50 H V C CNN
+F1 "Connector_Screw_Terminal_01x02" 0 -200 50 H V C CNN
+F2 "" 0 0 50 H I C CNN
+F3 "" 0 0 50 H I C CNN
+$FPLIST
+ TerminalBlock*:*
+$ENDFPLIST
+DRAW
+C 0 -100 25 1 1 6 N
+C 0 0 25 1 1 6 N
+S -50 50 50 -150 1 1 10 f
+P 2 1 1 6 -21 -87 13 -120 N
+P 2 1 1 6 -21 13 13 -20 N
+P 2 1 1 6 -14 -80 20 -113 N
+P 2 1 1 6 -14 20 20 -13 N
+X Pin_1 1 -200 0 150 R 50 50 1 1 P
+X Pin_2 2 -200 -100 150 R 50 50 1 1 P
+ENDDRAW
+ENDDEF
+#
+# Connector_Screw_Terminal_01x03
+#
+DEF Connector_Screw_Terminal_01x03 J 0 40 Y N 1 F N
+F0 "J" 0 200 50 H V C CNN
+F1 "Connector_Screw_Terminal_01x03" 0 -200 50 H V C CNN
+F2 "" 0 0 50 H I C CNN
+F3 "" 0 0 50 H I C CNN
+$FPLIST
+ TerminalBlock*:*
+$ENDFPLIST
+DRAW
+C 0 -100 25 1 1 6 N
+C 0 0 25 1 1 6 N
+C 0 100 25 1 1 6 N
+S -50 150 50 -150 1 1 10 f
+P 2 1 1 6 -21 -87 13 -120 N
+P 2 1 1 6 -21 13 13 -20 N
+P 2 1 1 6 -21 113 13 80 N
+P 2 1 1 6 -14 -80 20 -113 N
+P 2 1 1 6 -14 20 20 -13 N
+P 2 1 1 6 -14 120 20 87 N
+X Pin_1 1 -200 100 150 R 50 50 1 1 P
+X Pin_2 2 -200 0 150 R 50 50 1 1 P
+X Pin_3 3 -200 -100 150 R 50 50 1 1 P
+ENDDRAW
+ENDDEF
+#
+# Device_CP
+#
+DEF Device_CP C 0 10 N Y 1 F N
+F0 "C" 25 100 50 H V L CNN
+F1 "Device_CP" 25 -100 50 H V L CNN
+F2 "" 38 -150 50 H I C CNN
+F3 "" 0 0 50 H I C CNN
+$FPLIST
+ CP_*
+$ENDFPLIST
+DRAW
+S -90 20 90 40 0 1 0 N
+S 90 -20 -90 -40 0 1 0 F
+P 2 0 1 0 -70 90 -30 90 N
+P 2 0 1 0 -50 110 -50 70 N
+X ~ 1 0 150 110 D 50 50 1 1 P
+X ~ 2 0 -150 110 U 50 50 1 1 P
+ENDDRAW
+ENDDEF
+#
+# Device_LED
+#
+DEF Device_LED D 0 40 N N 1 F N
+F0 "D" 0 100 50 H V C CNN
+F1 "Device_LED" 0 -100 50 H V C CNN
+F2 "" 0 0 50 H I C CNN
+F3 "" 0 0 50 H I C CNN
+$FPLIST
+ LED*
+ LED_SMD:*
+ LED_THT:*
+$ENDFPLIST
+DRAW
+P 2 0 1 8 -50 -50 -50 50 N
+P 2 0 1 0 -50 0 50 0 N
+P 4 0 1 8 50 -50 50 50 -50 0 50 -50 N
+P 5 0 1 0 -120 -30 -180 -90 -150 -90 -180 -90 -180 -60 N
+P 5 0 1 0 -70 -30 -130 -90 -100 -90 -130 -90 -130 -60 N
+X K 1 -150 0 100 R 50 50 1 1 P
+X A 2 150 0 100 L 50 50 1 1 P
+ENDDRAW
+ENDDEF
+#
+# Device_R
+#
+DEF Device_R R 0 0 N Y 1 F N
+F0 "R" 80 0 50 V V C CNN
+F1 "Device_R" 0 0 50 V V C CNN
+F2 "" -70 0 50 V I C CNN
+F3 "" 0 0 50 H I C CNN
+$FPLIST
+ R_*
+$ENDFPLIST
+DRAW
+S -40 -100 40 100 0 1 10 N
+X ~ 1 0 150 50 D 50 50 1 1 P
+X ~ 2 0 -150 50 U 50 50 1 1 P
+ENDDRAW
+ENDDEF
+#
+# Diode_1N4001
+#
+DEF Diode_1N4001 D 0 40 N N 1 F N
+F0 "D" 0 100 50 H V C CNN
+F1 "Diode_1N4001" 0 -100 50 H V C CNN
+F2 "Diode_THT:D_DO-41_SOD81_P10.16mm_Horizontal" 0 -175 50 H I C CNN
+F3 "" 0 0 50 H I C CNN
+ALIAS 1N4002 1N4003 1N4004 1N4005 1N4006 1N4007 BA157 BA158 BA159
+$FPLIST
+ D*DO?41*
+$ENDFPLIST
+DRAW
+P 2 0 1 8 -50 50 -50 -50 N
+P 2 0 1 0 50 0 -50 0 N
+P 4 0 1 8 50 50 50 -50 -50 0 50 50 N
+X K 1 -150 0 100 R 50 50 1 1 P
+X A 2 150 0 100 L 50 50 1 1 P
+ENDDRAW
+ENDDEF
+#
+# Isolator_PC817
+#
+DEF Isolator_PC817 U 0 40 Y Y 1 F N
+F0 "U" -200 200 50 H V L CNN
+F1 "Isolator_PC817" 0 200 50 H V L CNN
+F2 "Package_DIP:DIP-4_W7.62mm" -200 -200 50 H I L CIN
+F3 "" 0 0 50 H I L CNN
+ALIAS EL817
+$FPLIST
+ DIP*W7.62mm*
+$ENDFPLIST
+DRAW
+S -200 150 200 -150 0 1 10 f
+P 2 0 1 10 -125 -25 -75 -25 N
+P 2 0 1 0 100 25 175 100 N
+P 2 0 1 0 175 -100 100 -25 F
+P 2 0 1 0 175 -100 200 -100 N
+P 2 0 1 0 175 100 200 100 N
+P 3 0 1 0 -200 100 -100 100 -100 -25 N
+P 3 0 1 0 -100 -25 -100 -100 -200 -100 N
+P 3 0 1 20 100 75 100 -75 100 -75 N
+P 4 0 1 10 -100 -25 -125 25 -75 25 -100 -25 N
+P 5 0 1 0 -20 -20 30 -20 15 -25 15 -15 30 -20 N
+P 5 0 1 0 -20 20 30 20 15 15 15 25 30 20 N
+P 5 0 1 0 120 -65 140 -45 160 -85 120 -65 120 -65 F
+X ~ 1 -300 100 100 R 50 50 1 1 P
+X ~ 2 -300 -100 100 R 50 50 1 1 P
+X ~ 3 300 -100 100 L 50 50 1 1 P
+X ~ 4 300 100 100 L 50 50 1 1 P
+ENDDRAW
+ENDDEF
+#
+# Modules-FloKra_ArduinoProMini_noAddHeaders
+#
+DEF Modules-FloKra_ArduinoProMini_noAddHeaders IC 0 40 Y Y 1 F N
+F0 "IC" -750 1250 40 H V L BNN
+F1 "Modules-FloKra_ArduinoProMini_noAddHeaders" 400 -1400 40 H V L BNN
+F2 "FloKra-Modules:ArduinoProMini_2" 0 0 30 H I C CIN
+F3 "" 0 0 60 H V C CNN
+$FPLIST
+ pro_mini*
+$ENDFPLIST
+DRAW
+S -750 1200 850 -1300 0 1 10 f
+X (PCINT17/TXD)PD1/1 1 1000 1000 150 L 40 40 1 1 B
+X (PCINT23/AIN1)PD7/7 10 1000 400 150 L 40 40 1 1 B
+X (PCINT0/CLKO/ICP1)PB0/8 11 1000 300 150 L 40 40 1 1 B
+X (PCINT1/OC1A/PWM)PB1/9 12 1000 200 150 L 40 40 1 1 B
+X (PCINT2/OC1B/~SS~/PWM)PB2/10 13 1000 100 150 L 40 40 1 1 B
+X (PCINT3/OC2A/MOSI/PWM)PB3/11 14 1000 -100 150 L 40 40 1 1 B
+X (PCINT4/MISO)PB4/12 15 1000 -200 150 L 40 40 1 1 B
+X (PCINT5/SCK)PB5/13 16 1000 -300 150 L 40 40 1 1 B
+X (PCINT8/ADC0)PC0/14/A0 17 1000 -500 150 L 40 40 1 1 B
+X (PCINT9/ADC1)PC1/15/A1 18 1000 -600 150 L 40 40 1 1 B
+X (PCINT10/ADC2)PC2/16/A2 19 1000 -700 150 L 40 40 1 1 B
+X (PCINT16/RXD)PD0/0 2 1000 1100 150 L 40 40 1 1 B
+X (PCINT11/ADC3)PC3/17/A3 20 1000 -800 150 L 40 40 1 1 B
+X VCC 21 -900 1100 150 R 40 40 1 1 W
+X (PCINT14/~RESET~)PC6 22 -900 -800 150 R 40 40 1 1 B
+X GND 23 -900 -1100 150 R 40 40 1 1 W
+X RAW 24 -900 800 150 R 40 40 1 1 W
+X (PCINT14/~RESET~)PC6 3 -900 -700 150 R 40 40 1 1 B
+X GND 4 -900 -1000 150 R 40 40 1 1 W
+X (PCINT18/INT0)PD2/2 5 1000 900 150 L 40 40 1 1 B
+X (PCINT19/OC2B/INT1/PWM)PD3/3 6 1000 800 150 L 40 40 1 1 B
+X (PCINT20/XCK/T0)PD4/4 7 1000 700 150 L 40 40 1 1 B
+X (PCINT21/OC0B/T1/PWM)PD5/5 8 1000 600 150 L 40 40 1 1 B
+X (PCINT22/OC0A/AIN0/PWM)PD6/6 9 1000 500 150 L 40 40 1 1 B
+ENDDRAW
+ENDDEF
+#
+# Regulator_Linear_L7805
+#
+DEF Regulator_Linear_L7805 U 0 10 Y Y 1 F N
+F0 "U" -150 125 50 H V C CNN
+F1 "Regulator_Linear_L7805" 0 125 50 H V L CNN
+F2 "" 25 -150 50 H I L CIN
+F3 "" 0 -50 50 H I C CNN
+ALIAS L7806 L7808 L7885 L7809 L7812 L7815 L7818 L7824
+$FPLIST
+ TO?252*
+ TO?263*
+ TO?220*
+$ENDFPLIST
+DRAW
+S -200 75 200 -200 0 1 10 f
+X IN 1 -300 0 100 R 50 50 1 1 W
+X GND 2 0 -300 100 U 50 50 1 1 W
+X OUT 3 300 0 100 L 50 50 1 1 w
+ENDDRAW
+ENDDEF
+#
+# power_+5V
+#
+DEF power_+5V #PWR 0 0 Y Y 1 F P
+F0 "#PWR" 0 -150 50 H I C CNN
+F1 "power_+5V" 0 140 50 H V C CNN
+F2 "" 0 0 50 H I C CNN
+F3 "" 0 0 50 H I C CNN
+DRAW
+P 2 0 1 0 -30 50 0 100 N
+P 2 0 1 0 0 0 0 100 N
+P 2 0 1 0 0 100 30 50 N
+X +5V 1 0 0 0 U 50 50 1 1 W N
+ENDDRAW
+ENDDEF
+#
+# power_GND
+#
+DEF power_GND #PWR 0 0 Y Y 1 F P
+F0 "#PWR" 0 -250 50 H I C CNN
+F1 "power_GND" 0 -150 50 H V C CNN
+F2 "" 0 0 50 H I C CNN
+F3 "" 0 0 50 H I C CNN
+DRAW
+P 6 0 1 0 0 0 0 -50 50 -50 0 -100 -50 -50 0 -50 N
+X GND 1 0 0 0 D 50 50 1 1 W N
+ENDDRAW
+ENDDEF
+#
+#End Library

+ 1417 - 0
Hardware/Schematics/ImpCounter.kicad_pcb

@@ -0,0 +1,1417 @@
+(kicad_pcb (version 20171130) (host pcbnew "(5.1.5)-3")
+
+  (general
+    (thickness 1.6)
+    (drawings 5)
+    (tracks 90)
+    (zones 0)
+    (modules 19)
+    (nets 32)
+  )
+
+  (page A4)
+  (layers
+    (0 F.Cu signal)
+    (31 B.Cu signal)
+    (32 B.Adhes user)
+    (33 F.Adhes user)
+    (34 B.Paste user)
+    (35 F.Paste user)
+    (36 B.SilkS user)
+    (37 F.SilkS user)
+    (38 B.Mask user)
+    (39 F.Mask user)
+    (40 Dwgs.User user)
+    (41 Cmts.User user)
+    (42 Eco1.User user)
+    (43 Eco2.User user)
+    (44 Edge.Cuts user)
+    (45 Margin user)
+    (46 B.CrtYd user)
+    (47 F.CrtYd user)
+    (48 B.Fab user)
+    (49 F.Fab user)
+  )
+
+  (setup
+    (last_trace_width 0.25)
+    (trace_clearance 0.2)
+    (zone_clearance 0.508)
+    (zone_45_only no)
+    (trace_min 0.2)
+    (via_size 0.8)
+    (via_drill 0.4)
+    (via_min_size 0.4)
+    (via_min_drill 0.3)
+    (uvia_size 0.3)
+    (uvia_drill 0.1)
+    (uvias_allowed no)
+    (uvia_min_size 0.2)
+    (uvia_min_drill 0.1)
+    (edge_width 0.1)
+    (segment_width 0.2)
+    (pcb_text_width 0.3)
+    (pcb_text_size 1.5 1.5)
+    (mod_edge_width 0.15)
+    (mod_text_size 1 1)
+    (mod_text_width 0.15)
+    (pad_size 1.524 1.524)
+    (pad_drill 0.762)
+    (pad_to_mask_clearance 0)
+    (aux_axis_origin 0 0)
+    (visible_elements FFFFFF7F)
+    (pcbplotparams
+      (layerselection 0x010fc_ffffffff)
+      (usegerberextensions false)
+      (usegerberattributes false)
+      (usegerberadvancedattributes false)
+      (creategerberjobfile false)
+      (excludeedgelayer true)
+      (linewidth 0.100000)
+      (plotframeref false)
+      (viasonmask false)
+      (mode 1)
+      (useauxorigin false)
+      (hpglpennumber 1)
+      (hpglpenspeed 20)
+      (hpglpendiameter 15.000000)
+      (psnegative false)
+      (psa4output false)
+      (plotreference true)
+      (plotvalue true)
+      (plotinvisibletext false)
+      (padsonsilk false)
+      (subtractmaskfromsilk false)
+      (outputformat 1)
+      (mirror false)
+      (drillshape 1)
+      (scaleselection 1)
+      (outputdirectory ""))
+  )
+
+  (net 0 "")
+  (net 1 "Net-(C1-Pad1)")
+  (net 2 GND)
+  (net 3 +5V)
+  (net 4 "Net-(D1-Pad2)")
+  (net 5 "Net-(D2-Pad1)")
+  (net 6 "Net-(D3-Pad1)")
+  (net 7 "Net-(J2-Pad2)")
+  (net 8 "Net-(J3-Pad2)")
+  (net 9 "Net-(Module1-Pad22)")
+  (net 10 "Net-(Module1-Pad21)")
+  (net 11 "Net-(Module1-Pad20)")
+  (net 12 "Net-(Module1-Pad19)")
+  (net 13 "Net-(Module1-Pad18)")
+  (net 14 "Net-(Module1-Pad17)")
+  (net 15 "Net-(Module1-Pad16)")
+  (net 16 "Net-(Module1-Pad15)")
+  (net 17 "Net-(Module1-Pad14)")
+  (net 18 "Net-(Module1-Pad13)")
+  (net 19 "Net-(Module1-Pad12)")
+  (net 20 "Net-(Module1-Pad11)")
+  (net 21 "Net-(Module1-Pad10)")
+  (net 22 "Net-(Module1-Pad3)")
+  (net 23 "Net-(Module1-Pad8)")
+  (net 24 "Net-(Module1-Pad7)")
+  (net 25 /MCU_INT1)
+  (net 26 /MCU_INT0)
+  (net 27 /MCU_RX)
+  (net 28 /MCU_TX)
+  (net 29 "Net-(R3-Pad1)")
+  (net 30 "Net-(R5-Pad1)")
+  (net 31 "Net-(D4-Pad1)")
+
+  (net_class Default "This is the default net class."
+    (clearance 0.2)
+    (trace_width 0.25)
+    (via_dia 0.8)
+    (via_drill 0.4)
+    (uvia_dia 0.3)
+    (uvia_drill 0.1)
+    (add_net +5V)
+    (add_net /MCU_INT0)
+    (add_net /MCU_INT1)
+    (add_net /MCU_RX)
+    (add_net /MCU_TX)
+    (add_net GND)
+    (add_net "Net-(C1-Pad1)")
+    (add_net "Net-(D1-Pad2)")
+    (add_net "Net-(D2-Pad1)")
+    (add_net "Net-(D3-Pad1)")
+    (add_net "Net-(D4-Pad1)")
+    (add_net "Net-(J2-Pad2)")
+    (add_net "Net-(J3-Pad2)")
+    (add_net "Net-(Module1-Pad10)")
+    (add_net "Net-(Module1-Pad11)")
+    (add_net "Net-(Module1-Pad12)")
+    (add_net "Net-(Module1-Pad13)")
+    (add_net "Net-(Module1-Pad14)")
+    (add_net "Net-(Module1-Pad15)")
+    (add_net "Net-(Module1-Pad16)")
+    (add_net "Net-(Module1-Pad17)")
+    (add_net "Net-(Module1-Pad18)")
+    (add_net "Net-(Module1-Pad19)")
+    (add_net "Net-(Module1-Pad20)")
+    (add_net "Net-(Module1-Pad21)")
+    (add_net "Net-(Module1-Pad22)")
+    (add_net "Net-(Module1-Pad3)")
+    (add_net "Net-(Module1-Pad7)")
+    (add_net "Net-(Module1-Pad8)")
+    (add_net "Net-(R3-Pad1)")
+    (add_net "Net-(R5-Pad1)")
+  )
+
+  (module Diodes_THT:D_DO-41_SOD81_P5.08mm_Vertical_AnodeUp (layer F.Cu) (tedit 5921392F) (tstamp 5F91E5A9)
+    (at 109.22 109.22)
+    (descr "D, DO-41_SOD81 series, Axial, Vertical, pin pitch=5.08mm, , length*diameter=5.2*2.7mm^2, , http://www.diodes.com/_files/packages/DO-41%20(Plastic).pdf")
+    (tags "D DO-41_SOD81 series Axial Vertical pin pitch 5.08mm  length 5.2mm diameter 2.7mm")
+    (path /5FA7B88E)
+    (fp_text reference D2 (at 5.08 -2.41) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value 1N4001 (at 5.08 2.41) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text user K (at -2.390635 0) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text user %R (at 5.08 0) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_line (start 0 0) (end 5.08 0) (layer F.Fab) (width 0.1))
+    (fp_line (start 1.690635 0) (end 3.68 0) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.947333 -0.889) (end 1.947333 0.889) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.947333 0) (end 3.132667 -0.889) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.132667 -0.889) (end 3.132667 0.889) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.132667 0.889) (end 1.947333 0) (layer F.SilkS) (width 0.12))
+    (fp_line (start -1.7 -1.95) (end -1.7 1.95) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -1.7 1.95) (end 6.5 1.95) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 6.5 1.95) (end 6.5 -1.95) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 6.5 -1.95) (end -1.7 -1.95) (layer F.CrtYd) (width 0.05))
+    (fp_circle (center 0 0) (end 1.35 0) (layer F.Fab) (width 0.1))
+    (fp_circle (center 0 0) (end 1.690635 0) (layer F.SilkS) (width 0.12))
+    (pad 1 thru_hole rect (at 0 0) (size 2.2 2.2) (drill 1.1) (layers *.Cu *.Mask)
+      (net 5 "Net-(D2-Pad1)"))
+    (pad 2 thru_hole oval (at 5.08 0) (size 2.2 2.2) (drill 1.1) (layers *.Cu *.Mask)
+      (net 4 "Net-(D1-Pad2)"))
+    (model ${KISYS3DMOD}/Diodes_THT.3dshapes/D_DO-41_SOD81_P5.08mm_Vertical_AnodeUp.wrl
+      (at (xyz 0 0 0))
+      (scale (xyz 0.393701 0.393701 0.393701))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (module Connectors_Terminal_Blocks:TerminalBlock_bornier-3_P5.08mm (layer F.Cu) (tedit 59FF03B9) (tstamp 5F917872)
+    (at 124.46 83.82 90)
+    (descr "simple 3-pin terminal block, pitch 5.08mm, revamped version of bornier3")
+    (tags "terminal block bornier3")
+    (path /5F9B713C)
+    (fp_text reference J3 (at 5.05 -4.65 90) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value IMP_IN_2 (at 5.08 5.08 90) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text user %R (at 5.08 0 90) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_line (start -2.47 2.55) (end 12.63 2.55) (layer F.Fab) (width 0.1))
+    (fp_line (start -2.47 -3.75) (end 12.63 -3.75) (layer F.Fab) (width 0.1))
+    (fp_line (start 12.63 -3.75) (end 12.63 3.75) (layer F.Fab) (width 0.1))
+    (fp_line (start 12.63 3.75) (end -2.47 3.75) (layer F.Fab) (width 0.1))
+    (fp_line (start -2.47 3.75) (end -2.47 -3.75) (layer F.Fab) (width 0.1))
+    (fp_line (start -2.54 3.81) (end -2.54 -3.81) (layer F.SilkS) (width 0.12))
+    (fp_line (start 12.7 3.81) (end 12.7 -3.81) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.54 2.54) (end 12.7 2.54) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.54 -3.81) (end 12.7 -3.81) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.54 3.81) (end 12.7 3.81) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.72 -4) (end 12.88 -4) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -2.72 -4) (end -2.72 4) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 12.88 4) (end 12.88 -4) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 12.88 4) (end -2.72 4) (layer F.CrtYd) (width 0.05))
+    (pad 1 thru_hole rect (at 0 0 90) (size 3 3) (drill 1.52) (layers *.Cu *.Mask)
+      (net 2 GND))
+    (pad 2 thru_hole circle (at 5.08 0 90) (size 3 3) (drill 1.52) (layers *.Cu *.Mask)
+      (net 8 "Net-(J3-Pad2)"))
+    (pad 3 thru_hole circle (at 10.16 0 90) (size 3 3) (drill 1.52) (layers *.Cu *.Mask)
+      (net 3 +5V))
+    (model ${KISYS3DMOD}/Terminal_Blocks.3dshapes/TerminalBlock_bornier-3_P5.08mm.wrl
+      (offset (xyz 5.079999923706055 0 0))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (module Capacitors_THT:CP_Radial_D10.0mm_P5.00mm (layer F.Cu) (tedit 597BC7C2) (tstamp 5F91785D)
+    (at 106.68 119.3 90)
+    (descr "CP, Radial series, Radial, pin pitch=5.00mm, , diameter=10mm, Electrolytic Capacitor")
+    (tags "CP Radial series Radial pin pitch 5.00mm  diameter 10mm Electrolytic Capacitor")
+    (path /5F84E231)
+    (fp_text reference C1 (at 2.5 -7.56 90) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value 2200u (at 2.5 7.56 90) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_arc (start 2.5 0) (end -2.399357 -1.38) (angle 148.5) (layer F.SilkS) (width 0.12))
+    (fp_arc (start 2.5 0) (end -2.399357 1.38) (angle -148.5) (layer F.SilkS) (width 0.12))
+    (fp_arc (start 2.5 0) (end 7.399357 -1.38) (angle 31.5) (layer F.SilkS) (width 0.12))
+    (fp_circle (center 2.5 0) (end 7.5 0) (layer F.Fab) (width 0.1))
+    (fp_line (start -2.7 0) (end -1.2 0) (layer F.Fab) (width 0.1))
+    (fp_line (start -1.95 -0.75) (end -1.95 0.75) (layer F.Fab) (width 0.1))
+    (fp_line (start 2.5 -5.05) (end 2.5 5.05) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.54 -5.05) (end 2.54 5.05) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.58 -5.05) (end 2.58 5.05) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.62 -5.049) (end 2.62 5.049) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.66 -5.048) (end 2.66 5.048) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.7 -5.047) (end 2.7 5.047) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.74 -5.045) (end 2.74 5.045) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.78 -5.043) (end 2.78 5.043) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.82 -5.04) (end 2.82 5.04) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.86 -5.038) (end 2.86 5.038) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.9 -5.035) (end 2.9 5.035) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.94 -5.031) (end 2.94 5.031) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.98 -5.028) (end 2.98 5.028) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.02 -5.024) (end 3.02 5.024) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.06 -5.02) (end 3.06 5.02) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.1 -5.015) (end 3.1 5.015) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.14 -5.01) (end 3.14 5.01) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.18 -5.005) (end 3.18 5.005) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.221 -4.999) (end 3.221 4.999) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.261 -4.993) (end 3.261 4.993) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.301 -4.987) (end 3.301 4.987) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.341 -4.981) (end 3.341 4.981) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.381 -4.974) (end 3.381 4.974) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.421 -4.967) (end 3.421 4.967) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.461 -4.959) (end 3.461 4.959) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.501 -4.951) (end 3.501 4.951) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.541 -4.943) (end 3.541 4.943) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.581 -4.935) (end 3.581 4.935) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.621 -4.926) (end 3.621 4.926) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.661 -4.917) (end 3.661 4.917) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.701 -4.907) (end 3.701 4.907) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.741 -4.897) (end 3.741 4.897) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.781 -4.887) (end 3.781 4.887) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.821 -4.876) (end 3.821 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.821 1.181) (end 3.821 4.876) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.861 -4.865) (end 3.861 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.861 1.181) (end 3.861 4.865) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.901 -4.854) (end 3.901 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.901 1.181) (end 3.901 4.854) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.941 -4.843) (end 3.941 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.941 1.181) (end 3.941 4.843) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.981 -4.831) (end 3.981 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.981 1.181) (end 3.981 4.831) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.021 -4.818) (end 4.021 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.021 1.181) (end 4.021 4.818) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.061 -4.806) (end 4.061 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.061 1.181) (end 4.061 4.806) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.101 -4.792) (end 4.101 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.101 1.181) (end 4.101 4.792) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.141 -4.779) (end 4.141 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.141 1.181) (end 4.141 4.779) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.181 -4.765) (end 4.181 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.181 1.181) (end 4.181 4.765) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.221 -4.751) (end 4.221 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.221 1.181) (end 4.221 4.751) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.261 -4.737) (end 4.261 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.261 1.181) (end 4.261 4.737) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.301 -4.722) (end 4.301 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.301 1.181) (end 4.301 4.722) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.341 -4.706) (end 4.341 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.341 1.181) (end 4.341 4.706) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.381 -4.691) (end 4.381 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.381 1.181) (end 4.381 4.691) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.421 -4.674) (end 4.421 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.421 1.181) (end 4.421 4.674) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.461 -4.658) (end 4.461 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.461 1.181) (end 4.461 4.658) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.501 -4.641) (end 4.501 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.501 1.181) (end 4.501 4.641) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.541 -4.624) (end 4.541 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.541 1.181) (end 4.541 4.624) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.581 -4.606) (end 4.581 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.581 1.181) (end 4.581 4.606) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.621 -4.588) (end 4.621 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.621 1.181) (end 4.621 4.588) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.661 -4.569) (end 4.661 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.661 1.181) (end 4.661 4.569) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.701 -4.55) (end 4.701 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.701 1.181) (end 4.701 4.55) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.741 -4.531) (end 4.741 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.741 1.181) (end 4.741 4.531) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.781 -4.511) (end 4.781 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.781 1.181) (end 4.781 4.511) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.821 -4.491) (end 4.821 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.821 1.181) (end 4.821 4.491) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.861 -4.47) (end 4.861 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.861 1.181) (end 4.861 4.47) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.901 -4.449) (end 4.901 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.901 1.181) (end 4.901 4.449) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.941 -4.428) (end 4.941 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.941 1.181) (end 4.941 4.428) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.981 -4.405) (end 4.981 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.981 1.181) (end 4.981 4.405) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.021 -4.383) (end 5.021 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.021 1.181) (end 5.021 4.383) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.061 -4.36) (end 5.061 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.061 1.181) (end 5.061 4.36) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.101 -4.336) (end 5.101 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.101 1.181) (end 5.101 4.336) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.141 -4.312) (end 5.141 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.141 1.181) (end 5.141 4.312) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.181 -4.288) (end 5.181 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.181 1.181) (end 5.181 4.288) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.221 -4.263) (end 5.221 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.221 1.181) (end 5.221 4.263) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.261 -4.237) (end 5.261 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.261 1.181) (end 5.261 4.237) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.301 -4.211) (end 5.301 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.301 1.181) (end 5.301 4.211) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.341 -4.185) (end 5.341 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.341 1.181) (end 5.341 4.185) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.381 -4.157) (end 5.381 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.381 1.181) (end 5.381 4.157) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.421 -4.13) (end 5.421 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.421 1.181) (end 5.421 4.13) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.461 -4.101) (end 5.461 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.461 1.181) (end 5.461 4.101) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.501 -4.072) (end 5.501 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.501 1.181) (end 5.501 4.072) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.541 -4.043) (end 5.541 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.541 1.181) (end 5.541 4.043) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.581 -4.013) (end 5.581 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.581 1.181) (end 5.581 4.013) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.621 -3.982) (end 5.621 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.621 1.181) (end 5.621 3.982) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.661 -3.951) (end 5.661 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.661 1.181) (end 5.661 3.951) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.701 -3.919) (end 5.701 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.701 1.181) (end 5.701 3.919) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.741 -3.886) (end 5.741 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.741 1.181) (end 5.741 3.886) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.781 -3.853) (end 5.781 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.781 1.181) (end 5.781 3.853) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.821 -3.819) (end 5.821 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.821 1.181) (end 5.821 3.819) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.861 -3.784) (end 5.861 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.861 1.181) (end 5.861 3.784) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.901 -3.748) (end 5.901 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.901 1.181) (end 5.901 3.748) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.941 -3.712) (end 5.941 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.941 1.181) (end 5.941 3.712) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.981 -3.675) (end 5.981 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 5.981 1.181) (end 5.981 3.675) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.021 -3.637) (end 6.021 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.021 1.181) (end 6.021 3.637) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.061 -3.598) (end 6.061 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.061 1.181) (end 6.061 3.598) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.101 -3.559) (end 6.101 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.101 1.181) (end 6.101 3.559) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.141 -3.518) (end 6.141 -1.181) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.141 1.181) (end 6.141 3.518) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.181 -3.477) (end 6.181 3.477) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.221 -3.435) (end 6.221 3.435) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.261 -3.391) (end 6.261 3.391) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.301 -3.347) (end 6.301 3.347) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.341 -3.302) (end 6.341 3.302) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.381 -3.255) (end 6.381 3.255) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.421 -3.207) (end 6.421 3.207) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.461 -3.158) (end 6.461 3.158) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.501 -3.108) (end 6.501 3.108) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.541 -3.057) (end 6.541 3.057) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.581 -3.004) (end 6.581 3.004) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.621 -2.949) (end 6.621 2.949) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.661 -2.894) (end 6.661 2.894) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.701 -2.836) (end 6.701 2.836) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.741 -2.777) (end 6.741 2.777) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.781 -2.715) (end 6.781 2.715) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.821 -2.652) (end 6.821 2.652) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.861 -2.587) (end 6.861 2.587) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.901 -2.519) (end 6.901 2.519) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.941 -2.449) (end 6.941 2.449) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.981 -2.377) (end 6.981 2.377) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.021 -2.301) (end 7.021 2.301) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.061 -2.222) (end 7.061 2.222) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.101 -2.14) (end 7.101 2.14) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.141 -2.053) (end 7.141 2.053) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.181 -1.962) (end 7.181 1.962) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.221 -1.866) (end 7.221 1.866) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.261 -1.763) (end 7.261 1.763) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.301 -1.654) (end 7.301 1.654) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.341 -1.536) (end 7.341 1.536) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.381 -1.407) (end 7.381 1.407) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.421 -1.265) (end 7.421 1.265) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.461 -1.104) (end 7.461 1.104) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.501 -0.913) (end 7.501 0.913) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.541 -0.672) (end 7.541 0.672) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.581 -0.279) (end 7.581 0.279) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.7 0) (end -1.2 0) (layer F.SilkS) (width 0.12))
+    (fp_line (start -1.95 -0.75) (end -1.95 0.75) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.85 -5.35) (end -2.85 5.35) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -2.85 5.35) (end 7.85 5.35) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 7.85 5.35) (end 7.85 -5.35) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 7.85 -5.35) (end -2.85 -5.35) (layer F.CrtYd) (width 0.05))
+    (fp_text user %R (at 2.5 0 90) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (pad 1 thru_hole rect (at 0 0 90) (size 2 2) (drill 1) (layers *.Cu *.Mask)
+      (net 1 "Net-(C1-Pad1)"))
+    (pad 2 thru_hole circle (at 5 0 90) (size 2 2) (drill 1) (layers *.Cu *.Mask)
+      (net 2 GND))
+    (model ${KISYS3DMOD}/Capacitors_THT.3dshapes/CP_Radial_D10.0mm_P5.00mm.wrl
+      (at (xyz 0 0 0))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (module Diodes_THT:D_DO-201AD_P5.08mm_Vertical_KathodeUp (layer F.Cu) (tedit 5921392E) (tstamp 5F917863)
+    (at 114.3 119.38 90)
+    (descr "D, DO-201AD series, Axial, Vertical, pin pitch=5.08mm, , length*diameter=9.5*5.2mm^2, , http://www.diodes.com/_files/packages/DO-201AD.pdf")
+    (tags "D DO-201AD series Axial Vertical pin pitch 5.08mm  length 9.5mm diameter 5.2mm")
+    (path /5F84C042)
+    (fp_text reference D1 (at 5.08 -2.41 90) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value 1N4001 (at 5.08 2.41 90) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text user K (at -2.3 0 90) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text user %R (at 5.08 0 90) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_line (start 0 0) (end 5.08 0) (layer F.Fab) (width 0.1))
+    (fp_line (start 2.66 0) (end 3.18 0) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.794 1.78) (end 2.794 3.558) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.794 2.669) (end 3.979333 1.78) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.979333 1.78) (end 3.979333 3.558) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.979333 3.558) (end 2.794 2.669) (layer F.SilkS) (width 0.12))
+    (fp_line (start -1.95 -2.95) (end -1.95 2.95) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -1.95 2.95) (end 8 2.95) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 8 2.95) (end 8 -2.95) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 8 -2.95) (end -1.95 -2.95) (layer F.CrtYd) (width 0.05))
+    (fp_circle (center 5.08 0) (end 7.68 0) (layer F.Fab) (width 0.1))
+    (fp_circle (center 5.08 0) (end 7.74 0) (layer F.SilkS) (width 0.12))
+    (pad 1 thru_hole rect (at 0 0 90) (size 3.2 3.2) (drill 1.6) (layers *.Cu *.Mask)
+      (net 1 "Net-(C1-Pad1)"))
+    (pad 2 thru_hole oval (at 5.08 0 90) (size 3.2 3.2) (drill 1.6) (layers *.Cu *.Mask)
+      (net 4 "Net-(D1-Pad2)"))
+    (model ${KISYS3DMOD}/Diodes_THT.3dshapes/D_DO-201AD_P5.08mm_Vertical_KathodeUp.wrl
+      (at (xyz 0 0 0))
+      (scale (xyz 0.393701 0.393701 0.393701))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (module Resistors_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P7.62mm_Horizontal (layer F.Cu) (tedit 5874F706) (tstamp 5F91789F)
+    (at 101.6 91.44 270)
+    (descr "Resistor, Axial_DIN0207 series, Axial, Horizontal, pin pitch=7.62mm, 0.25W = 1/4W, length*diameter=6.3*2.5mm^2, http://cdn-reichelt.de/documents/datenblatt/B400/1_4W%23YAG.pdf")
+    (tags "Resistor Axial_DIN0207 series Axial Horizontal pin pitch 7.62mm 0.25W = 1/4W length 6.3mm diameter 2.5mm")
+    (path /5F8629E7)
+    (fp_text reference R2 (at 2.54 -2.31 90) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value 24k (at 2.54 2.31 90) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_line (start 0.66 -1.25) (end 0.66 1.25) (layer F.Fab) (width 0.1))
+    (fp_line (start 0.66 1.25) (end 6.96 1.25) (layer F.Fab) (width 0.1))
+    (fp_line (start 6.96 1.25) (end 6.96 -1.25) (layer F.Fab) (width 0.1))
+    (fp_line (start 6.96 -1.25) (end 0.66 -1.25) (layer F.Fab) (width 0.1))
+    (fp_line (start 0 0) (end 0.66 0) (layer F.Fab) (width 0.1))
+    (fp_line (start 7.62 0) (end 6.96 0) (layer F.Fab) (width 0.1))
+    (fp_line (start 0.6 -0.98) (end 0.6 -1.31) (layer F.SilkS) (width 0.12))
+    (fp_line (start 0.6 -1.31) (end 7.02 -1.31) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.02 -1.31) (end 7.02 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 0.6 0.98) (end 0.6 1.31) (layer F.SilkS) (width 0.12))
+    (fp_line (start 0.6 1.31) (end 7.02 1.31) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.02 1.31) (end 7.02 0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start -1.05 -1.6) (end -1.05 1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -1.05 1.6) (end 8.7 1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 8.7 1.6) (end 8.7 -1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 8.7 -1.6) (end -1.05 -1.6) (layer F.CrtYd) (width 0.05))
+    (pad 1 thru_hole circle (at 0 0 270) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 11 "Net-(Module1-Pad20)"))
+    (pad 2 thru_hole oval (at 7.62 0 270) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 2 GND))
+    (model ${KISYS3DMOD}/Resistors_THT.3dshapes/R_Axial_DIN0207_L6.3mm_D2.5mm_P7.62mm_Horizontal.wrl
+      (at (xyz 0 0 0))
+      (scale (xyz 0.393701 0.393701 0.393701))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (module Resistors_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P7.62mm_Horizontal (layer F.Cu) (tedit 5874F706) (tstamp 5F91789C)
+    (at 96.52 99.06 90)
+    (descr "Resistor, Axial_DIN0207 series, Axial, Horizontal, pin pitch=7.62mm, 0.25W = 1/4W, length*diameter=6.3*2.5mm^2, http://cdn-reichelt.de/documents/datenblatt/B400/1_4W%23YAG.pdf")
+    (tags "Resistor Axial_DIN0207 series Axial Horizontal pin pitch 7.62mm 0.25W = 1/4W length 6.3mm diameter 2.5mm")
+    (path /5F860BAB)
+    (fp_text reference R1 (at 2.54 -2.31 90) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value 56k (at 2.54 2.31 90) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_line (start 0.66 -1.25) (end 0.66 1.25) (layer F.Fab) (width 0.1))
+    (fp_line (start 0.66 1.25) (end 6.96 1.25) (layer F.Fab) (width 0.1))
+    (fp_line (start 6.96 1.25) (end 6.96 -1.25) (layer F.Fab) (width 0.1))
+    (fp_line (start 6.96 -1.25) (end 0.66 -1.25) (layer F.Fab) (width 0.1))
+    (fp_line (start 0 0) (end 0.66 0) (layer F.Fab) (width 0.1))
+    (fp_line (start 7.62 0) (end 6.96 0) (layer F.Fab) (width 0.1))
+    (fp_line (start 0.6 -0.98) (end 0.6 -1.31) (layer F.SilkS) (width 0.12))
+    (fp_line (start 0.6 -1.31) (end 7.02 -1.31) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.02 -1.31) (end 7.02 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 0.6 0.98) (end 0.6 1.31) (layer F.SilkS) (width 0.12))
+    (fp_line (start 0.6 1.31) (end 7.02 1.31) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.02 1.31) (end 7.02 0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start -1.05 -1.6) (end -1.05 1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -1.05 1.6) (end 8.7 1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 8.7 1.6) (end 8.7 -1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 8.7 -1.6) (end -1.05 -1.6) (layer F.CrtYd) (width 0.05))
+    (pad 1 thru_hole circle (at 0 0 90) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 1 "Net-(C1-Pad1)"))
+    (pad 2 thru_hole oval (at 7.62 0 90) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 11 "Net-(Module1-Pad20)"))
+    (model ${KISYS3DMOD}/Resistors_THT.3dshapes/R_Axial_DIN0207_L6.3mm_D2.5mm_P7.62mm_Horizontal.wrl
+      (at (xyz 0 0 0))
+      (scale (xyz 0.393701 0.393701 0.393701))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (module FloKra_Modules:ArduinoProMini_noAdditionalHeaders (layer F.Cu) (tedit 5F9179BE) (tstamp 5F917899)
+    (at 99.06 87.63 90)
+    (descr "IC, ARDUINO_PRO_MINI x 0,6\"")
+    (tags "DIL ARDUINO PRO MINI")
+    (path /5F80A727)
+    (fp_text reference Module1 (at -13.97 10.16 90) (layer F.SilkS)
+      (effects (font (size 0.8 0.8) (thickness 0.16)))
+    )
+    (fp_text value ArduinoProMini (at 0 0 90) (layer F.Fab) hide
+      (effects (font (size 0.8 0.8) (thickness 0.16)))
+    )
+    (fp_line (start -17.526 -8.89) (end 15.24 -8.89) (layer F.SilkS) (width 0.15))
+    (fp_line (start 15.24 9.144) (end -17.526 9.144) (layer F.SilkS) (width 0.15))
+    (fp_line (start -17.526 -8.89) (end -17.526 9.144) (layer F.SilkS) (width 0.15))
+    (fp_line (start 15.24 9.144) (end 15.24 -8.89) (layer F.SilkS) (width 0.15))
+    (pad 24 thru_hole oval (at -13.97 -7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 1 "Net-(C1-Pad1)"))
+    (pad 23 thru_hole oval (at -11.43 -7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 2 GND))
+    (pad 22 thru_hole oval (at -8.89 -7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 9 "Net-(Module1-Pad22)"))
+    (pad 21 thru_hole oval (at -6.35 -7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 10 "Net-(Module1-Pad21)"))
+    (pad 20 thru_hole oval (at -3.81 -7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 11 "Net-(Module1-Pad20)"))
+    (pad 19 thru_hole oval (at -1.27 -7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 12 "Net-(Module1-Pad19)"))
+    (pad 18 thru_hole oval (at 1.27 -7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 13 "Net-(Module1-Pad18)"))
+    (pad 17 thru_hole oval (at 3.81 -7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 14 "Net-(Module1-Pad17)"))
+    (pad 16 thru_hole oval (at 6.35 -7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 15 "Net-(Module1-Pad16)"))
+    (pad 15 thru_hole oval (at 8.89 -7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 16 "Net-(Module1-Pad15)"))
+    (pad 14 thru_hole oval (at 11.43 -7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 17 "Net-(Module1-Pad14)"))
+    (pad 13 thru_hole oval (at 13.97 -7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 18 "Net-(Module1-Pad13)"))
+    (pad 12 thru_hole oval (at 13.97 7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 19 "Net-(Module1-Pad12)"))
+    (pad 11 thru_hole oval (at 11.43 7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 20 "Net-(Module1-Pad11)"))
+    (pad 10 thru_hole oval (at 8.89 7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 21 "Net-(Module1-Pad10)"))
+    (pad 9 thru_hole oval (at 6.35 7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 22 "Net-(Module1-Pad3)"))
+    (pad 8 thru_hole oval (at 3.81 7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 23 "Net-(Module1-Pad8)"))
+    (pad 7 thru_hole oval (at 1.27 7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 24 "Net-(Module1-Pad7)"))
+    (pad 6 thru_hole oval (at -1.27 7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 25 /MCU_INT1))
+    (pad 5 thru_hole oval (at -3.81 7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 26 /MCU_INT0))
+    (pad 4 thru_hole oval (at -6.35 7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 2 GND))
+    (pad 3 thru_hole oval (at -8.89 7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 22 "Net-(Module1-Pad3)"))
+    (pad 2 thru_hole oval (at -11.43 7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 27 /MCU_RX))
+    (pad 1 thru_hole oval (at -13.97 7.62 90) (size 1.50114 2.19964) (drill 0.8001) (layers *.Cu *.Mask F.SilkS)
+      (net 28 /MCU_TX))
+    (model Socket_Strips.3dshapes/Socket_Strip_Straight_1x02_Pitch2.54mm.wrl
+      (offset (xyz -3.809999942779541 5.079999923706055 0))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+    (model Socket_Strips.3dshapes/Socket_Strip_Straight_1x03_Pitch2.54mm.wrl
+      (offset (xyz 13.96999979019165 2.539999961853027 0))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 90))
+    )
+    (model Socket_Strips.3dshapes/Socket_Strip_Straight_1x12_Pitch2.54mm.wrl
+      (offset (xyz 0 7.619999885559082 0))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+    (model Socket_Strips.3dshapes/Socket_Strip_Straight_1x12_Pitch2.54mm.wrl
+      (offset (xyz 0 -7.619999885559082 0))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+    (model Socket_Strips.3dshapes/Socket_Strip_Straight_1x02_Pitch2.54mm.wrl
+      (offset (xyz 6.349999904632568 5.079999923706055 0))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+    (model ${MYSLOCAL}/mysensors.3dshapes/mysensors_arduino.3dshapes/arduino_pro_mini.wrl
+      (offset (xyz -1.269999980926514 0 12.19199981689453))
+      (scale (xyz 0.395 0.395 0.395))
+      (rotate (xyz 0 0 180))
+    )
+    (model SMD_Packages.3dshapes/TQFP-32.wrl
+      (offset (xyz 1.269999980926514 0 13.01749980449676))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 315))
+    )
+    (model Pin_Headers.3dshapes/Pin_Header_Straight_1x12_Pitch2.54mm.wrl
+      (offset (xyz 13.96999979019165 -7.619999885559082 11.30299983024597))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 180 90))
+    )
+    (model Pin_Headers.3dshapes/Pin_Header_Straight_1x12_Pitch2.54mm.wrl
+      (offset (xyz 13.96999979019165 7.619999885559082 11.30299983024597))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 180 90))
+    )
+    (model Pin_Headers.3dshapes/Pin_Header_Straight_1x03_Pitch2.54mm.wrl
+      (offset (xyz 13.96999979019165 5.079999923706055 11.30299983024597))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 180 0))
+    )
+    (model Pin_Headers.3dshapes/Pin_Header_Straight_1x02_Pitch2.54mm.wrl
+      (offset (xyz 7.619999885559082 5.079999923706055 11.30299983024597))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 180 90))
+    )
+    (model Pin_Headers.3dshapes/Pin_Header_Straight_1x02_Pitch2.54mm.wrl
+      (offset (xyz -2.539999961853027 5.079999923706055 11.30299983024597))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 180 90))
+    )
+    (model ${MYSLOCAL}/mysensors.3dshapes/w.lain.3dshapes/smd_leds/led_0603.wrl
+      (offset (xyz -7.619999885559082 0 13.01749980449676))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+    (model ${MYSLOCAL}/mysensors.3dshapes/w.lain.3dshapes/smd_leds/led_0603.wrl
+      (offset (xyz 13.96999979019165 -4.444999933242798 13.01749980449676))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+    (model Pin_Headers.3dshapes/Pin_Header_Angled_1x06_Pitch2.54mm.wrl
+      (offset (xyz -16.50999975204468 -6.349999904632568 13.01749980449676))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 180))
+    )
+    (model Resistors_SMD.3dshapes/R_0603.wrl
+      (offset (xyz -7.619999885559082 -1.269999980926514 13.01749980449676))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+    (model Resistors_SMD.3dshapes/R_0603.wrl
+      (offset (xyz 13.96999979019165 -3.174999952316284 13.01749980449676))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+    (model Capacitors_SMD.3dshapes/C_0603.wrl
+      (offset (xyz -7.619999885559082 1.269999980926514 13.01749980449676))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+    (model Capacitors_Tantalum_SMD.3dshapes/CP_Tantalum_Case-S_EIA-3216-12.wrl
+      (offset (xyz -8.889999866485596 3.809999942779541 13.01749980449676))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+    (model Capacitors_Tantalum_SMD.3dshapes/CP_Tantalum_Case-S_EIA-3216-12.wrl
+      (offset (xyz -8.889999866485596 -3.809999942779541 13.01749980449676))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+    (model TO_SOT_Packages_SMD.3dshapes/SOT-23-5.wrl
+      (offset (xyz -10.15999984741211 0 13.01749980449676))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 90))
+    )
+    (model Capacitors_SMD.3dshapes/C_1210.wrl
+      (offset (xyz -12.69999980926514 0 13.01749980449676))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 90))
+    )
+    (model ${MYSLOCAL}/mysensors.3dshapes/w.lain.3dshapes/switch/smd_push.wrl
+      (offset (xyz 10.15999984741211 0 13.01749980449676))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 90))
+    )
+  )
+
+  (module Resistors_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P2.54mm_Vertical (layer F.Cu) (tedit 5874F706) (tstamp 5F9178A2)
+    (at 116.84 93.98)
+    (descr "Resistor, Axial_DIN0207 series, Axial, Vertical, pin pitch=2.54mm, 0.25W = 1/4W, length*diameter=6.3*2.5mm^2, http://cdn-reichelt.de/documents/datenblatt/B400/1_4W%23YAG.pdf")
+    (tags "Resistor Axial_DIN0207 series Axial Vertical pin pitch 2.54mm 0.25W = 1/4W length 6.3mm diameter 2.5mm")
+    (path /5F94A6CF)
+    (fp_text reference R3 (at 2.54 -2.31) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value 560 (at 2.54 2.31) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_circle (center 0 0) (end 1.25 0) (layer F.Fab) (width 0.1))
+    (fp_circle (center 0 0) (end 1.31 0) (layer F.SilkS) (width 0.12))
+    (fp_line (start 0 0) (end 2.54 0) (layer F.Fab) (width 0.1))
+    (fp_line (start 1.31 0) (end 1.44 0) (layer F.SilkS) (width 0.12))
+    (fp_line (start -1.6 -1.6) (end -1.6 1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -1.6 1.6) (end 3.65 1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 3.65 1.6) (end 3.65 -1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 3.65 -1.6) (end -1.6 -1.6) (layer F.CrtYd) (width 0.05))
+    (pad 1 thru_hole circle (at 0 0) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 29 "Net-(R3-Pad1)"))
+    (pad 2 thru_hole oval (at 2.54 0) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 7 "Net-(J2-Pad2)"))
+    (model ${KISYS3DMOD}/Resistors_THT.3dshapes/R_Axial_DIN0207_L6.3mm_D2.5mm_P2.54mm_Vertical.wrl
+      (at (xyz 0 0 0))
+      (scale (xyz 0.393701 0.393701 0.393701))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (module Resistors_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P2.54mm_Vertical (layer F.Cu) (tedit 5874F706) (tstamp 5F9178A5)
+    (at 116.84 91.44)
+    (descr "Resistor, Axial_DIN0207 series, Axial, Vertical, pin pitch=2.54mm, 0.25W = 1/4W, length*diameter=6.3*2.5mm^2, http://cdn-reichelt.de/documents/datenblatt/B400/1_4W%23YAG.pdf")
+    (tags "Resistor Axial_DIN0207 series Axial Vertical pin pitch 2.54mm 0.25W = 1/4W length 6.3mm diameter 2.5mm")
+    (path /5F9A2208)
+    (fp_text reference R4 (at 2.54 -2.31) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value 560 (at 2.54 2.31) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_circle (center 0 0) (end 1.25 0) (layer F.Fab) (width 0.1))
+    (fp_circle (center 0 0) (end 1.31 0) (layer F.SilkS) (width 0.12))
+    (fp_line (start 0 0) (end 2.54 0) (layer F.Fab) (width 0.1))
+    (fp_line (start 1.31 0) (end 1.44 0) (layer F.SilkS) (width 0.12))
+    (fp_line (start -1.6 -1.6) (end -1.6 1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -1.6 1.6) (end 3.65 1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 3.65 1.6) (end 3.65 -1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 3.65 -1.6) (end -1.6 -1.6) (layer F.CrtYd) (width 0.05))
+    (pad 1 thru_hole circle (at 0 0) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 6 "Net-(D3-Pad1)"))
+    (pad 2 thru_hole oval (at 2.54 0) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 7 "Net-(J2-Pad2)"))
+    (model ${KISYS3DMOD}/Resistors_THT.3dshapes/R_Axial_DIN0207_L6.3mm_D2.5mm_P2.54mm_Vertical.wrl
+      (at (xyz 0 0 0))
+      (scale (xyz 0.393701 0.393701 0.393701))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (module Resistors_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P2.54mm_Vertical (layer F.Cu) (tedit 5874F706) (tstamp 5F9178AB)
+    (at 116.84 76.2)
+    (descr "Resistor, Axial_DIN0207 series, Axial, Vertical, pin pitch=2.54mm, 0.25W = 1/4W, length*diameter=6.3*2.5mm^2, http://cdn-reichelt.de/documents/datenblatt/B400/1_4W%23YAG.pdf")
+    (tags "Resistor Axial_DIN0207 series Axial Vertical pin pitch 2.54mm 0.25W = 1/4W length 6.3mm diameter 2.5mm")
+    (path /5F9B716A)
+    (fp_text reference R6 (at 2.54 -2.31) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value 560 (at 2.54 2.31) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_circle (center 0 0) (end 1.25 0) (layer F.Fab) (width 0.1))
+    (fp_circle (center 0 0) (end 1.31 0) (layer F.SilkS) (width 0.12))
+    (fp_line (start 0 0) (end 2.54 0) (layer F.Fab) (width 0.1))
+    (fp_line (start 1.31 0) (end 1.44 0) (layer F.SilkS) (width 0.12))
+    (fp_line (start -1.6 -1.6) (end -1.6 1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -1.6 1.6) (end 3.65 1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 3.65 1.6) (end 3.65 -1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 3.65 -1.6) (end -1.6 -1.6) (layer F.CrtYd) (width 0.05))
+    (pad 1 thru_hole circle (at 0 0) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 31 "Net-(D4-Pad1)"))
+    (pad 2 thru_hole oval (at 2.54 0) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 8 "Net-(J3-Pad2)"))
+    (model ${KISYS3DMOD}/Resistors_THT.3dshapes/R_Axial_DIN0207_L6.3mm_D2.5mm_P2.54mm_Vertical.wrl
+      (at (xyz 0 0 0))
+      (scale (xyz 0.393701 0.393701 0.393701))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (module Resistors_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P2.54mm_Vertical (layer F.Cu) (tedit 5874F706) (tstamp 5F9178A8)
+    (at 116.84 78.74)
+    (descr "Resistor, Axial_DIN0207 series, Axial, Vertical, pin pitch=2.54mm, 0.25W = 1/4W, length*diameter=6.3*2.5mm^2, http://cdn-reichelt.de/documents/datenblatt/B400/1_4W%23YAG.pdf")
+    (tags "Resistor Axial_DIN0207 series Axial Vertical pin pitch 2.54mm 0.25W = 1/4W length 6.3mm diameter 2.5mm")
+    (path /5F9B7149)
+    (fp_text reference R5 (at 2.54 -2.31) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value 560 (at 2.54 2.31) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_circle (center 0 0) (end 1.25 0) (layer F.Fab) (width 0.1))
+    (fp_circle (center 0 0) (end 1.31 0) (layer F.SilkS) (width 0.12))
+    (fp_line (start 0 0) (end 2.54 0) (layer F.Fab) (width 0.1))
+    (fp_line (start 1.31 0) (end 1.44 0) (layer F.SilkS) (width 0.12))
+    (fp_line (start -1.6 -1.6) (end -1.6 1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -1.6 1.6) (end 3.65 1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 3.65 1.6) (end 3.65 -1.6) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 3.65 -1.6) (end -1.6 -1.6) (layer F.CrtYd) (width 0.05))
+    (pad 1 thru_hole circle (at 0 0) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 30 "Net-(R5-Pad1)"))
+    (pad 2 thru_hole oval (at 2.54 0) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 8 "Net-(J3-Pad2)"))
+    (model ${KISYS3DMOD}/Resistors_THT.3dshapes/R_Axial_DIN0207_L6.3mm_D2.5mm_P2.54mm_Vertical.wrl
+      (at (xyz 0 0 0))
+      (scale (xyz 0.393701 0.393701 0.393701))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (module Housings_DIP:DIP-4_W7.62mm (layer F.Cu) (tedit 59C78D6B) (tstamp 5F9178B4)
+    (at 119.38 83.82 180)
+    (descr "4-lead though-hole mounted DIP package, row spacing 7.62 mm (300 mils)")
+    (tags "THT DIP DIL PDIP 2.54mm 7.62mm 300mil")
+    (path /5F9B7136)
+    (fp_text reference U3 (at 3.81 -2.33) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value PC817 (at 3.81 4.87) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_arc (start 3.81 -1.33) (end 2.81 -1.33) (angle -180) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.635 -1.27) (end 6.985 -1.27) (layer F.Fab) (width 0.1))
+    (fp_line (start 6.985 -1.27) (end 6.985 3.81) (layer F.Fab) (width 0.1))
+    (fp_line (start 6.985 3.81) (end 0.635 3.81) (layer F.Fab) (width 0.1))
+    (fp_line (start 0.635 3.81) (end 0.635 -0.27) (layer F.Fab) (width 0.1))
+    (fp_line (start 0.635 -0.27) (end 1.635 -1.27) (layer F.Fab) (width 0.1))
+    (fp_line (start 2.81 -1.33) (end 1.16 -1.33) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.16 -1.33) (end 1.16 3.87) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.16 3.87) (end 6.46 3.87) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.46 3.87) (end 6.46 -1.33) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.46 -1.33) (end 4.81 -1.33) (layer F.SilkS) (width 0.12))
+    (fp_line (start -1.1 -1.55) (end -1.1 4.1) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -1.1 4.1) (end 8.7 4.1) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 8.7 4.1) (end 8.7 -1.55) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 8.7 -1.55) (end -1.1 -1.55) (layer F.CrtYd) (width 0.05))
+    (fp_text user %R (at 3.81 1.27) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (pad 1 thru_hole rect (at 0 0 180) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 3 +5V))
+    (pad 3 thru_hole oval (at 7.62 2.54 180) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 2 GND))
+    (pad 2 thru_hole oval (at 0 2.54 180) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 30 "Net-(R5-Pad1)"))
+    (pad 4 thru_hole oval (at 7.62 0 180) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 25 /MCU_INT1))
+    (model ${KISYS3DMOD}/Housings_DIP.3dshapes/DIP-4_W7.62mm.wrl
+      (at (xyz 0 0 0))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (module Housings_DIP:DIP-4_W7.62mm (layer F.Cu) (tedit 59C78D6B) (tstamp 5F9178B1)
+    (at 119.38 99.06 180)
+    (descr "4-lead though-hole mounted DIP package, row spacing 7.62 mm (300 mils)")
+    (tags "THT DIP DIL PDIP 2.54mm 7.62mm 300mil")
+    (path /5F925BDD)
+    (fp_text reference U2 (at 3.81 -2.33) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value PC817 (at 3.81 4.87) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_arc (start 3.81 -1.33) (end 2.81 -1.33) (angle -180) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.635 -1.27) (end 6.985 -1.27) (layer F.Fab) (width 0.1))
+    (fp_line (start 6.985 -1.27) (end 6.985 3.81) (layer F.Fab) (width 0.1))
+    (fp_line (start 6.985 3.81) (end 0.635 3.81) (layer F.Fab) (width 0.1))
+    (fp_line (start 0.635 3.81) (end 0.635 -0.27) (layer F.Fab) (width 0.1))
+    (fp_line (start 0.635 -0.27) (end 1.635 -1.27) (layer F.Fab) (width 0.1))
+    (fp_line (start 2.81 -1.33) (end 1.16 -1.33) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.16 -1.33) (end 1.16 3.87) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.16 3.87) (end 6.46 3.87) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.46 3.87) (end 6.46 -1.33) (layer F.SilkS) (width 0.12))
+    (fp_line (start 6.46 -1.33) (end 4.81 -1.33) (layer F.SilkS) (width 0.12))
+    (fp_line (start -1.1 -1.55) (end -1.1 4.1) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -1.1 4.1) (end 8.7 4.1) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 8.7 4.1) (end 8.7 -1.55) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 8.7 -1.55) (end -1.1 -1.55) (layer F.CrtYd) (width 0.05))
+    (fp_text user %R (at 3.81 0.804999) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (pad 1 thru_hole rect (at 0 0 180) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 3 +5V))
+    (pad 3 thru_hole oval (at 7.62 2.54 180) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 2 GND))
+    (pad 2 thru_hole oval (at 0 2.54 180) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 29 "Net-(R3-Pad1)"))
+    (pad 4 thru_hole oval (at 7.62 0 180) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 26 /MCU_INT0))
+    (model ${KISYS3DMOD}/Housings_DIP.3dshapes/DIP-4_W7.62mm.wrl
+      (at (xyz 0 0 0))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (module TO_SOT_Packages_THT:TO-220-3_Vertical (layer F.Cu) (tedit 58CE52AD) (tstamp 5F9178AE)
+    (at 111.76 104.14)
+    (descr "TO-220-3, Vertical, RM 2.54mm")
+    (tags "TO-220-3 Vertical RM 2.54mm")
+    (path /5F94F630)
+    (fp_text reference U1 (at 2.54 -3.62) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value L7805 (at 2.54 3.92) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text user %R (at 2.54 -3.62) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_line (start -2.46 -2.5) (end -2.46 1.9) (layer F.Fab) (width 0.1))
+    (fp_line (start -2.46 1.9) (end 7.54 1.9) (layer F.Fab) (width 0.1))
+    (fp_line (start 7.54 1.9) (end 7.54 -2.5) (layer F.Fab) (width 0.1))
+    (fp_line (start 7.54 -2.5) (end -2.46 -2.5) (layer F.Fab) (width 0.1))
+    (fp_line (start -2.46 -1.23) (end 7.54 -1.23) (layer F.Fab) (width 0.1))
+    (fp_line (start 0.69 -2.5) (end 0.69 -1.23) (layer F.Fab) (width 0.1))
+    (fp_line (start 4.39 -2.5) (end 4.39 -1.23) (layer F.Fab) (width 0.1))
+    (fp_line (start -2.58 -2.62) (end 7.66 -2.62) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.58 2.021) (end 7.66 2.021) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.58 -2.62) (end -2.58 2.021) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.66 -2.62) (end 7.66 2.021) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.58 -1.11) (end 7.66 -1.11) (layer F.SilkS) (width 0.12))
+    (fp_line (start 0.69 -2.62) (end 0.69 -1.11) (layer F.SilkS) (width 0.12))
+    (fp_line (start 4.391 -2.62) (end 4.391 -1.11) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.71 -2.75) (end -2.71 2.16) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -2.71 2.16) (end 7.79 2.16) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 7.79 2.16) (end 7.79 -2.75) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 7.79 -2.75) (end -2.71 -2.75) (layer F.CrtYd) (width 0.05))
+    (pad 1 thru_hole rect (at 0 0) (size 1.8 1.8) (drill 1) (layers *.Cu *.Mask)
+      (net 5 "Net-(D2-Pad1)"))
+    (pad 2 thru_hole oval (at 2.54 0) (size 1.8 1.8) (drill 1) (layers *.Cu *.Mask)
+      (net 2 GND))
+    (pad 3 thru_hole oval (at 5.08 0) (size 1.8 1.8) (drill 1) (layers *.Cu *.Mask)
+      (net 3 +5V))
+    (model ${KISYS3DMOD}/TO_SOT_Packages_THT.3dshapes/TO-220-3_Vertical.wrl
+      (offset (xyz 2.539999961853027 0 0))
+      (scale (xyz 0.393701 0.393701 0.393701))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (module Connectors_Terminal_Blocks:TerminalBlock_bornier-3_P5.08mm (layer F.Cu) (tedit 59FF03B9) (tstamp 5F91786F)
+    (at 124.46 99.06 90)
+    (descr "simple 3-pin terminal block, pitch 5.08mm, revamped version of bornier3")
+    (tags "terminal block bornier3")
+    (path /5F92B88F)
+    (fp_text reference J2 (at 5.05 -4.65 90) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value IMP_IN_1 (at 5.08 5.08 90) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text user %R (at 5.08 0 90) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_line (start -2.47 2.55) (end 12.63 2.55) (layer F.Fab) (width 0.1))
+    (fp_line (start -2.47 -3.75) (end 12.63 -3.75) (layer F.Fab) (width 0.1))
+    (fp_line (start 12.63 -3.75) (end 12.63 3.75) (layer F.Fab) (width 0.1))
+    (fp_line (start 12.63 3.75) (end -2.47 3.75) (layer F.Fab) (width 0.1))
+    (fp_line (start -2.47 3.75) (end -2.47 -3.75) (layer F.Fab) (width 0.1))
+    (fp_line (start -2.54 3.81) (end -2.54 -3.81) (layer F.SilkS) (width 0.12))
+    (fp_line (start 12.7 3.81) (end 12.7 -3.81) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.54 2.54) (end 12.7 2.54) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.54 -3.81) (end 12.7 -3.81) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.54 3.81) (end 12.7 3.81) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.72 -4) (end 12.88 -4) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -2.72 -4) (end -2.72 4) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 12.88 4) (end 12.88 -4) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 12.88 4) (end -2.72 4) (layer F.CrtYd) (width 0.05))
+    (pad 1 thru_hole rect (at 0 0 90) (size 3 3) (drill 1.52) (layers *.Cu *.Mask)
+      (net 2 GND))
+    (pad 2 thru_hole circle (at 5.08 0 90) (size 3 3) (drill 1.52) (layers *.Cu *.Mask)
+      (net 7 "Net-(J2-Pad2)"))
+    (pad 3 thru_hole circle (at 10.16 0 90) (size 3 3) (drill 1.52) (layers *.Cu *.Mask)
+      (net 3 +5V))
+    (model ${KISYS3DMOD}/Terminal_Blocks.3dshapes/TerminalBlock_bornier-3_P5.08mm.wrl
+      (offset (xyz 5.079999923706055 0 0))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (module Connectors_Terminal_Blocks:TerminalBlock_bornier-2_P5.08mm (layer F.Cu) (tedit 59FF03AB) (tstamp 5F91786C)
+    (at 119.38 116.84)
+    (descr "simple 2-pin terminal block, pitch 5.08mm, revamped version of bornier2")
+    (tags "terminal block bornier2")
+    (path /5F843696)
+    (fp_text reference J1 (at 2.54 -5.08) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value "Supply 9-12 VDC" (at 2.54 5.08) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text user %R (at 2.54 0) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_line (start -2.41 2.55) (end 7.49 2.55) (layer F.Fab) (width 0.1))
+    (fp_line (start -2.46 -3.75) (end -2.46 3.75) (layer F.Fab) (width 0.1))
+    (fp_line (start -2.46 3.75) (end 7.54 3.75) (layer F.Fab) (width 0.1))
+    (fp_line (start 7.54 3.75) (end 7.54 -3.75) (layer F.Fab) (width 0.1))
+    (fp_line (start 7.54 -3.75) (end -2.46 -3.75) (layer F.Fab) (width 0.1))
+    (fp_line (start 7.62 2.54) (end -2.54 2.54) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.62 3.81) (end 7.62 -3.81) (layer F.SilkS) (width 0.12))
+    (fp_line (start 7.62 -3.81) (end -2.54 -3.81) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.54 -3.81) (end -2.54 3.81) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.54 3.81) (end 7.62 3.81) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.71 -4) (end 7.79 -4) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -2.71 -4) (end -2.71 4) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 7.79 4) (end 7.79 -4) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 7.79 4) (end -2.71 4) (layer F.CrtYd) (width 0.05))
+    (pad 1 thru_hole rect (at 0 0) (size 3 3) (drill 1.52) (layers *.Cu *.Mask)
+      (net 4 "Net-(D1-Pad2)"))
+    (pad 2 thru_hole circle (at 5.08 0) (size 3 3) (drill 1.52) (layers *.Cu *.Mask)
+      (net 2 GND))
+    (model ${KISYS3DMOD}/Terminal_Blocks.3dshapes/TerminalBlock_bornier-2_P5.08mm.wrl
+      (offset (xyz 2.539999961853027 0 0))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (module LEDs:LED_D3.0mm (layer F.Cu) (tedit 587A3A7B) (tstamp 5F917869)
+    (at 114.3 76.2 180)
+    (descr "LED, diameter 3.0mm, 2 pins")
+    (tags "LED diameter 3.0mm 2 pins")
+    (path /5F9B7161)
+    (fp_text reference D4 (at 1.27 -2.96) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value LED (at 1.27 2.96) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_arc (start 1.27 0) (end -0.23 -1.16619) (angle 284.3) (layer F.Fab) (width 0.1))
+    (fp_arc (start 1.27 0) (end -0.29 -1.235516) (angle 108.8) (layer F.SilkS) (width 0.12))
+    (fp_arc (start 1.27 0) (end -0.29 1.235516) (angle -108.8) (layer F.SilkS) (width 0.12))
+    (fp_arc (start 1.27 0) (end 0.229039 -1.08) (angle 87.9) (layer F.SilkS) (width 0.12))
+    (fp_arc (start 1.27 0) (end 0.229039 1.08) (angle -87.9) (layer F.SilkS) (width 0.12))
+    (fp_circle (center 1.27 0) (end 2.77 0) (layer F.Fab) (width 0.1))
+    (fp_line (start -0.23 -1.16619) (end -0.23 1.16619) (layer F.Fab) (width 0.1))
+    (fp_line (start -0.29 -1.236) (end -0.29 -1.08) (layer F.SilkS) (width 0.12))
+    (fp_line (start -0.29 1.08) (end -0.29 1.236) (layer F.SilkS) (width 0.12))
+    (fp_line (start -1.15 -2.25) (end -1.15 2.25) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -1.15 2.25) (end 3.7 2.25) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 3.7 2.25) (end 3.7 -2.25) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 3.7 -2.25) (end -1.15 -2.25) (layer F.CrtYd) (width 0.05))
+    (pad 1 thru_hole rect (at 0 0 180) (size 1.8 1.8) (drill 0.9) (layers *.Cu *.Mask)
+      (net 31 "Net-(D4-Pad1)"))
+    (pad 2 thru_hole circle (at 2.54 0 180) (size 1.8 1.8) (drill 0.9) (layers *.Cu *.Mask)
+      (net 3 +5V))
+    (model ${KISYS3DMOD}/LEDs.3dshapes/LED_D3.0mm.wrl
+      (at (xyz 0 0 0))
+      (scale (xyz 0.393701 0.393701 0.393701))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (module LEDs:LED_D3.0mm (layer F.Cu) (tedit 587A3A7B) (tstamp 5F917866)
+    (at 114.3 91.44 180)
+    (descr "LED, diameter 3.0mm, 2 pins")
+    (tags "LED diameter 3.0mm 2 pins")
+    (path /5F983BBB)
+    (fp_text reference D3 (at 1.27 -2.96) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value LED (at 1.27 2.96) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_arc (start 1.27 0) (end -0.23 -1.16619) (angle 284.3) (layer F.Fab) (width 0.1))
+    (fp_arc (start 1.27 0) (end -0.29 -1.235516) (angle 108.8) (layer F.SilkS) (width 0.12))
+    (fp_arc (start 1.27 0) (end -0.29 1.235516) (angle -108.8) (layer F.SilkS) (width 0.12))
+    (fp_arc (start 1.27 0) (end 0.229039 -1.08) (angle 87.9) (layer F.SilkS) (width 0.12))
+    (fp_arc (start 1.27 0) (end 0.229039 1.08) (angle -87.9) (layer F.SilkS) (width 0.12))
+    (fp_circle (center 1.27 0) (end 2.77 0) (layer F.Fab) (width 0.1))
+    (fp_line (start -0.23 -1.16619) (end -0.23 1.16619) (layer F.Fab) (width 0.1))
+    (fp_line (start -0.29 -1.236) (end -0.29 -1.08) (layer F.SilkS) (width 0.12))
+    (fp_line (start -0.29 1.08) (end -0.29 1.236) (layer F.SilkS) (width 0.12))
+    (fp_line (start -1.15 -2.25) (end -1.15 2.25) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -1.15 2.25) (end 3.7 2.25) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 3.7 2.25) (end 3.7 -2.25) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 3.7 -2.25) (end -1.15 -2.25) (layer F.CrtYd) (width 0.05))
+    (pad 1 thru_hole rect (at 0 0 180) (size 1.8 1.8) (drill 0.9) (layers *.Cu *.Mask)
+      (net 6 "Net-(D3-Pad1)"))
+    (pad 2 thru_hole circle (at 2.54 0 180) (size 1.8 1.8) (drill 0.9) (layers *.Cu *.Mask)
+      (net 3 +5V))
+    (model ${KISYS3DMOD}/LEDs.3dshapes/LED_D3.0mm.wrl
+      (at (xyz 0 0 0))
+      (scale (xyz 0.393701 0.393701 0.393701))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (module Capacitors_THT:CP_Radial_D5.0mm_P2.50mm (layer F.Cu) (tedit 597BC7C2) (tstamp 5F917860)
+    (at 121.92 104.14)
+    (descr "CP, Radial series, Radial, pin pitch=2.50mm, , diameter=5mm, Electrolytic Capacitor")
+    (tags "CP Radial series Radial pin pitch 2.50mm  diameter 5mm Electrolytic Capacitor")
+    (path /5F88AF10)
+    (fp_text reference C2 (at 1.25 -3.81) (layer F.SilkS)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_text value 47u (at 1.25 3.81) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (fp_arc (start 1.25 0) (end -1.05558 -1.18) (angle 125.8) (layer F.SilkS) (width 0.12))
+    (fp_arc (start 1.25 0) (end -1.05558 1.18) (angle -125.8) (layer F.SilkS) (width 0.12))
+    (fp_arc (start 1.25 0) (end 3.55558 -1.18) (angle 54.2) (layer F.SilkS) (width 0.12))
+    (fp_circle (center 1.25 0) (end 3.75 0) (layer F.Fab) (width 0.1))
+    (fp_line (start -2.2 0) (end -1 0) (layer F.Fab) (width 0.1))
+    (fp_line (start -1.6 -0.65) (end -1.6 0.65) (layer F.Fab) (width 0.1))
+    (fp_line (start 1.25 -2.55) (end 1.25 2.55) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.29 -2.55) (end 1.29 2.55) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.33 -2.549) (end 1.33 2.549) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.37 -2.548) (end 1.37 2.548) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.41 -2.546) (end 1.41 2.546) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.45 -2.543) (end 1.45 2.543) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.49 -2.539) (end 1.49 2.539) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.53 -2.535) (end 1.53 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.53 0.98) (end 1.53 2.535) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.57 -2.531) (end 1.57 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.57 0.98) (end 1.57 2.531) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.61 -2.525) (end 1.61 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.61 0.98) (end 1.61 2.525) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.65 -2.519) (end 1.65 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.65 0.98) (end 1.65 2.519) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.69 -2.513) (end 1.69 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.69 0.98) (end 1.69 2.513) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.73 -2.506) (end 1.73 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.73 0.98) (end 1.73 2.506) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.77 -2.498) (end 1.77 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.77 0.98) (end 1.77 2.498) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.81 -2.489) (end 1.81 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.81 0.98) (end 1.81 2.489) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.85 -2.48) (end 1.85 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.85 0.98) (end 1.85 2.48) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.89 -2.47) (end 1.89 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.89 0.98) (end 1.89 2.47) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.93 -2.46) (end 1.93 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.93 0.98) (end 1.93 2.46) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.971 -2.448) (end 1.971 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 1.971 0.98) (end 1.971 2.448) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.011 -2.436) (end 2.011 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.011 0.98) (end 2.011 2.436) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.051 -2.424) (end 2.051 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.051 0.98) (end 2.051 2.424) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.091 -2.41) (end 2.091 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.091 0.98) (end 2.091 2.41) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.131 -2.396) (end 2.131 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.131 0.98) (end 2.131 2.396) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.171 -2.382) (end 2.171 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.171 0.98) (end 2.171 2.382) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.211 -2.366) (end 2.211 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.211 0.98) (end 2.211 2.366) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.251 -2.35) (end 2.251 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.251 0.98) (end 2.251 2.35) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.291 -2.333) (end 2.291 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.291 0.98) (end 2.291 2.333) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.331 -2.315) (end 2.331 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.331 0.98) (end 2.331 2.315) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.371 -2.296) (end 2.371 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.371 0.98) (end 2.371 2.296) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.411 -2.276) (end 2.411 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.411 0.98) (end 2.411 2.276) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.451 -2.256) (end 2.451 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.451 0.98) (end 2.451 2.256) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.491 -2.234) (end 2.491 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.491 0.98) (end 2.491 2.234) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.531 -2.212) (end 2.531 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.531 0.98) (end 2.531 2.212) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.571 -2.189) (end 2.571 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.571 0.98) (end 2.571 2.189) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.611 -2.165) (end 2.611 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.611 0.98) (end 2.611 2.165) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.651 -2.14) (end 2.651 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.651 0.98) (end 2.651 2.14) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.691 -2.113) (end 2.691 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.691 0.98) (end 2.691 2.113) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.731 -2.086) (end 2.731 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.731 0.98) (end 2.731 2.086) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.771 -2.058) (end 2.771 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.771 0.98) (end 2.771 2.058) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.811 -2.028) (end 2.811 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.811 0.98) (end 2.811 2.028) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.851 -1.997) (end 2.851 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.851 0.98) (end 2.851 1.997) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.891 -1.965) (end 2.891 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.891 0.98) (end 2.891 1.965) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.931 -1.932) (end 2.931 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.931 0.98) (end 2.931 1.932) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.971 -1.897) (end 2.971 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 2.971 0.98) (end 2.971 1.897) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.011 -1.861) (end 3.011 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.011 0.98) (end 3.011 1.861) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.051 -1.823) (end 3.051 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.051 0.98) (end 3.051 1.823) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.091 -1.783) (end 3.091 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.091 0.98) (end 3.091 1.783) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.131 -1.742) (end 3.131 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.131 0.98) (end 3.131 1.742) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.171 -1.699) (end 3.171 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.171 0.98) (end 3.171 1.699) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.211 -1.654) (end 3.211 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.211 0.98) (end 3.211 1.654) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.251 -1.606) (end 3.251 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.251 0.98) (end 3.251 1.606) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.291 -1.556) (end 3.291 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.291 0.98) (end 3.291 1.556) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.331 -1.504) (end 3.331 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.331 0.98) (end 3.331 1.504) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.371 -1.448) (end 3.371 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.371 0.98) (end 3.371 1.448) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.411 -1.39) (end 3.411 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.411 0.98) (end 3.411 1.39) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.451 -1.327) (end 3.451 -0.98) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.451 0.98) (end 3.451 1.327) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.491 -1.261) (end 3.491 1.261) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.531 -1.189) (end 3.531 1.189) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.571 -1.112) (end 3.571 1.112) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.611 -1.028) (end 3.611 1.028) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.651 -0.934) (end 3.651 0.934) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.691 -0.829) (end 3.691 0.829) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.731 -0.707) (end 3.731 0.707) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.771 -0.559) (end 3.771 0.559) (layer F.SilkS) (width 0.12))
+    (fp_line (start 3.811 -0.354) (end 3.811 0.354) (layer F.SilkS) (width 0.12))
+    (fp_line (start -2.2 0) (end -1 0) (layer F.SilkS) (width 0.12))
+    (fp_line (start -1.6 -0.65) (end -1.6 0.65) (layer F.SilkS) (width 0.12))
+    (fp_line (start -1.6 -2.85) (end -1.6 2.85) (layer F.CrtYd) (width 0.05))
+    (fp_line (start -1.6 2.85) (end 4.1 2.85) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 4.1 2.85) (end 4.1 -2.85) (layer F.CrtYd) (width 0.05))
+    (fp_line (start 4.1 -2.85) (end -1.6 -2.85) (layer F.CrtYd) (width 0.05))
+    (fp_text user %R (at 1.25 0) (layer F.Fab)
+      (effects (font (size 1 1) (thickness 0.15)))
+    )
+    (pad 1 thru_hole rect (at 0 0) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 3 +5V))
+    (pad 2 thru_hole circle (at 2.5 0) (size 1.6 1.6) (drill 0.8) (layers *.Cu *.Mask)
+      (net 2 GND))
+    (model ${KISYS3DMOD}/Capacitors_THT.3dshapes/CP_Radial_D5.0mm_P2.50mm.wrl
+      (at (xyz 0 0 0))
+      (scale (xyz 1 1 1))
+      (rotate (xyz 0 0 0))
+    )
+  )
+
+  (gr_line (start 124.46 68.58) (end 91.44 68.58) (layer B.SilkS) (width 0.15) (tstamp 5F91D4DD))
+  (gr_line (start 167.64 71.12) (end 134.62 71.12) (layer B.SilkS) (width 0.15) (tstamp 5F91D407))
+  (gr_line (start 167.64 119.38) (end 167.64 71.12) (layer B.SilkS) (width 0.15))
+  (gr_line (start 134.62 119.38) (end 167.64 119.38) (layer B.SilkS) (width 0.15))
+  (gr_line (start 134.62 71.12) (end 134.62 119.38) (layer B.SilkS) (width 0.15))
+
+  (via (at 104.14 96.52) (size 0.8) (drill 0.4) (layers F.Cu B.Cu) (net 22))
+  (via (at 104.14 81.28) (size 0.8) (drill 0.4) (layers F.Cu B.Cu) (net 22))
+  (segment (start 96.52 101.6) (end 91.44 101.6) (width 0.25) (layer B.Cu) (net 1))
+  (segment (start 96.52 101.6) (end 96.52 99.06) (width 0.25) (layer B.Cu) (net 1))
+  (segment (start 106.76 119.38) (end 106.68 119.3) (width 0.25) (layer B.Cu) (net 1))
+  (segment (start 114.3 119.38) (end 106.76 119.38) (width 0.25) (layer B.Cu) (net 1))
+  (segment (start 106.68 119.3) (end 91.52 119.3) (width 0.25) (layer B.Cu) (net 1))
+  (segment (start 91.44 119.22) (end 91.44 101.6) (width 0.25) (layer B.Cu) (net 1))
+  (segment (start 91.52 119.3) (end 91.44 119.22) (width 0.25) (layer B.Cu) (net 1))
+  (segment (start 91.44 99.06) (end 93.98 99.06) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 93.98 99.06) (end 93.98 93.98) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 93.98 93.98) (end 101.6 93.98) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 114.3 104.14) (end 114.3 101.6) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 104.14 93.98) (end 106.68 93.98) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 101.6 93.98) (end 104.14 93.98) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 111.76 96.52) (end 114.3 99.06) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 114.3 101.6) (end 114.3 99.06) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 114.3 104.14) (end 114.3 106.68) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 114.3 106.68) (end 111.76 106.68) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 111.76 106.68) (end 111.76 111.76) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 111.76 111.76) (end 109.22 114.3) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 109.22 114.3) (end 106.68 114.3) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 106.68 104.14) (end 106.68 106.68) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 101.6 93.98) (end 101.6 104.14) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 106.68 106.68) (end 106.68 114.3) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 101.6 104.14) (end 106.68 104.14) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 124.46 104.18) (end 124.42 104.14) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 124.42 99.1) (end 124.46 99.06) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 124.42 104.14) (end 124.42 99.1) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 114.3 106.68) (end 124.46 106.68) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 124.46 116.84) (end 124.46 106.68) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 124.46 106.68) (end 124.46 104.18) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 127 85.72359) (end 124.778205 83.501795) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 124.46 99.06) (end 127 96.52) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 127 96.52) (end 127 85.72359) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 111.76 81.28) (end 109.22 81.28) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 109.22 81.28) (end 109.22 71.12) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 109.22 71.12) (end 101.6 71.12) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 101.6 71.12) (end 101.6 86.36) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 101.6 86.36) (end 104.14 88.9) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 104.14 88.9) (end 104.14 93.98) (width 0.25) (layer B.Cu) (net 2))
+  (segment (start 119.38 99.06) (end 116.84 99.06) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 116.84 99.06) (end 114.3 96.52) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 114.3 96.52) (end 114.3 93.98) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 114.3 93.98) (end 111.76 93.98) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 111.76 91.44) (end 111.76 93.98) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 111.76 91.44) (end 111.76 88.9) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 111.76 88.9) (end 114.3 88.9) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 114.3 88.9) (end 119.38 83.82) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 111.76 76.2) (end 111.76 78.74) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 111.76 78.74) (end 116.84 83.82) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 116.84 83.82) (end 119.38 83.82) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 116.84 104.14) (end 121.92 104.14) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 120.43 99.06) (end 119.38 99.06) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 121.92 100.55) (end 120.43 99.06) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 121.92 104.14) (end 121.92 100.55) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 119.38 83.82) (end 119.38 86.36) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 121.92 88.9) (end 124.46 88.9) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 119.38 86.36) (end 121.92 88.9) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 127 81.28) (end 127 76.2) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 127 76.2) (end 124.46 73.66) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 119.38 83.82) (end 121.92 81.28) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 121.92 81.28) (end 127 81.28) (width 0.25) (layer B.Cu) (net 3))
+  (segment (start 119.38 116.84) (end 116.84 114.3) (width 0.25) (layer B.Cu) (net 4))
+  (segment (start 116.84 114.3) (end 114.3 114.3) (width 0.25) (layer B.Cu) (net 4))
+  (segment (start 114.3 109.22) (end 114.3 114.3) (width 0.25) (layer B.Cu) (net 4))
+  (segment (start 110.61 104.14) (end 111.76 104.14) (width 0.25) (layer B.Cu) (net 5))
+  (segment (start 109.22 105.53) (end 110.61 104.14) (width 0.25) (layer B.Cu) (net 5))
+  (segment (start 109.22 109.22) (end 109.22 105.53) (width 0.25) (layer B.Cu) (net 5))
+  (segment (start 114.3 91.44) (end 116.84 91.44) (width 0.25) (layer B.Cu) (net 6))
+  (segment (start 116.84 76.2) (end 114.3 76.2) (width 0.25) (layer B.Cu) (net 31))
+  (segment (start 119.38 91.44) (end 119.38 93.98) (width 0.25) (layer B.Cu) (net 7))
+  (segment (start 124.46 93.98) (end 119.38 93.98) (width 0.25) (layer B.Cu) (net 7))
+  (segment (start 119.38 78.74) (end 124.46 78.74) (width 0.25) (layer B.Cu) (net 8))
+  (segment (start 119.38 78.74) (end 119.38 76.2) (width 0.25) (layer B.Cu) (net 8))
+  (segment (start 96.52 91.44) (end 101.6 91.44) (width 0.25) (layer B.Cu) (net 11))
+  (segment (start 91.44 91.44) (end 96.52 91.44) (width 0.25) (layer B.Cu) (net 11))
+  (segment (start 104.14 81.28) (end 104.14 96.52) (width 0.25) (layer F.Cu) (net 22))
+  (segment (start 104.14 96.52) (end 106.68 96.52) (width 0.25) (layer B.Cu) (net 22))
+  (segment (start 104.14 81.28) (end 106.68 81.28) (width 0.25) (layer B.Cu) (net 22))
+  (segment (start 106.68 88.9) (end 109.22 88.9) (width 0.25) (layer B.Cu) (net 25))
+  (segment (start 109.22 88.9) (end 111.76 86.36) (width 0.25) (layer B.Cu) (net 25))
+  (segment (start 111.76 86.36) (end 111.76 83.82) (width 0.25) (layer B.Cu) (net 25))
+  (segment (start 111.76 99.06) (end 109.22 99.06) (width 0.25) (layer B.Cu) (net 26))
+  (segment (start 109.22 99.06) (end 109.22 91.44) (width 0.25) (layer B.Cu) (net 26))
+  (segment (start 109.22 91.44) (end 106.68 91.44) (width 0.25) (layer B.Cu) (net 26))
+  (segment (start 119.38 96.52) (end 116.84 96.52) (width 0.25) (layer B.Cu) (net 29))
+  (segment (start 116.84 96.52) (end 116.84 93.98) (width 0.25) (layer B.Cu) (net 29))
+  (segment (start 119.38 81.28) (end 116.84 81.28) (width 0.25) (layer B.Cu) (net 30))
+  (segment (start 116.84 81.28) (end 116.84 78.74) (width 0.25) (layer B.Cu) (net 30))
+
+)

+ 33 - 0
Hardware/Schematics/ImpCounter.pro

@@ -0,0 +1,33 @@
+update=22/05/2015 07:44:53
+version=1
+last_client=kicad
+[general]
+version=1
+RootSch=
+BoardNm=
+[pcbnew]
+version=1
+LastNetListRead=
+UseCmpFile=1
+PadDrill=0.600000000000
+PadDrillOvalY=0.600000000000
+PadSizeH=1.500000000000
+PadSizeV=1.500000000000
+PcbTextSizeV=1.500000000000
+PcbTextSizeH=1.500000000000
+PcbTextThickness=0.300000000000
+ModuleTextSizeV=1.000000000000
+ModuleTextSizeH=1.000000000000
+ModuleTextSizeThickness=0.150000000000
+SolderMaskClearance=0.000000000000
+SolderMaskMinWidth=0.000000000000
+DrawSegmentWidth=0.200000000000
+BoardOutlineThickness=0.100000000000
+ModuleOutlineThickness=0.150000000000
+[cvpcb]
+version=1
+NetIExt=net
+[eeschema]
+version=1
+LibDir=
+[eeschema/libraries]

+ 549 - 0
Hardware/Schematics/ImpCounter.sch

@@ -0,0 +1,549 @@
+EESchema Schematic File Version 4
+EELAYER 30 0
+EELAYER END
+$Descr A4 11693 8268
+encoding utf-8
+Sheet 1 1
+Title ""
+Date ""
+Rev ""
+Comp ""
+Comment1 ""
+Comment2 ""
+Comment3 ""
+Comment4 ""
+$EndDescr
+$Comp
+L Modules-FloKra:ArduinoProMini_noAddHeaders Module1
+U 1 1 5F80A727
+P 5500 2950
+F 0 "Module1" H 5550 4294 40  0000 C CNN
+F 1 "ArduinoProMini" H 5550 4218 40  0000 C CNN
+F 2 "FloKra_Modules:ArduinoProMini_V2wCrystal_allHeaders" H 5500 2950 30  0001 C CIN
+F 3 "" H 5550 4233 60  0000 C CNN
+	1    5500 2950
+	1    0    0    -1  
+$EndComp
+Wire Wire Line
+	4350 4750 4350 3650
+Text Notes 4450 4750 0    35   ~ 0
+reset from software used for firmware flashing w/o DTR line connected
+$Comp
+L power:GND #PWR0101
+U 1 1 5F820294
+P 4500 4350
+F 0 "#PWR0101" H 4500 4100 50  0001 C CNN
+F 1 "GND" H 4505 4177 50  0000 C CNN
+F 2 "" H 4500 4350 50  0001 C CNN
+F 3 "" H 4500 4350 50  0001 C CNN
+	1    4500 4350
+	1    0    0    -1  
+$EndComp
+Wire Wire Line
+	4600 4150 4500 4150
+Wire Wire Line
+	4500 4150 4500 4350
+Wire Wire Line
+	4500 4150 4500 4050
+Wire Wire Line
+	4500 4050 4600 4050
+Connection ~ 4500 4150
+Wire Wire Line
+	4500 4050 4500 3950
+Wire Wire Line
+	4500 3950 4600 3950
+Connection ~ 4500 4050
+Wire Wire Line
+	6500 2450 6700 2450
+Wire Wire Line
+	6700 2450 6700 4750
+$Comp
+L Connector:Screw_Terminal_01x02 J1
+U 1 1 5F843696
+P 1300 1050
+F 0 "J1" H 1218 1267 50  0000 C CNN
+F 1 "Supply 9-12 VDC" H 1218 1175 50  0000 C CNN
+F 2 "Connectors_Terminal_Blocks:TerminalBlock_bornier-2_P5.08mm" H 1300 1050 50  0001 C CNN
+F 3 "~" H 1300 1050 50  0001 C CNN
+	1    1300 1050
+	-1   0    0    -1  
+$EndComp
+$Comp
+L power:GND #PWR0102
+U 1 1 5F844655
+P 1500 1300
+F 0 "#PWR0102" H 1500 1050 50  0001 C CNN
+F 1 "GND" H 1505 1127 50  0000 C CNN
+F 2 "" H 1500 1300 50  0001 C CNN
+F 3 "" H 1500 1300 50  0001 C CNN
+	1    1500 1300
+	1    0    0    -1  
+$EndComp
+Wire Wire Line
+	1500 1150 1500 1300
+$Comp
+L Diode:1N4001 D1
+U 1 1 5F84C042
+P 2250 1450
+F 0 "D1" V 2296 1371 50  0000 R CNN
+F 1 "1N4001" V 2205 1371 50  0000 R CNN
+F 2 "Diodes_THT:D_DO-41_SOD81_P10.16mm_Horizontal" H 2250 1275 50  0001 C CNN
+F 3 "http://www.vishay.com/docs/88503/1n4001.pdf" H 2250 1450 50  0001 C CNN
+	1    2250 1450
+	0    -1   -1   0   
+$EndComp
+Wire Wire Line
+	2250 1050 2250 1300
+$Comp
+L Device:CP C1
+U 1 1 5F84E231
+P 2250 1950
+F 0 "C1" H 2368 1996 50  0000 L CNN
+F 1 "2200u" H 2368 1905 50  0000 L CNN
+F 2 "Capacitors_THT:CP_Radial_D12.5mm_P5.00mm" H 2288 1800 50  0001 C CNN
+F 3 "~" H 2250 1950 50  0001 C CNN
+	1    2250 1950
+	1    0    0    -1  
+$EndComp
+$Comp
+L power:GND #PWR0103
+U 1 1 5F84EA75
+P 2250 2250
+F 0 "#PWR0103" H 2250 2000 50  0001 C CNN
+F 1 "GND" H 2255 2077 50  0000 C CNN
+F 2 "" H 2250 2250 50  0001 C CNN
+F 3 "" H 2250 2250 50  0001 C CNN
+	1    2250 2250
+	1    0    0    -1  
+$EndComp
+Wire Wire Line
+	2250 2100 2250 2250
+$Comp
+L power:GND #PWR0104
+U 1 1 5F853210
+P 3650 1400
+F 0 "#PWR0104" H 3650 1150 50  0001 C CNN
+F 1 "GND" H 3655 1227 50  0000 C CNN
+F 2 "" H 3650 1400 50  0001 C CNN
+F 3 "" H 3650 1400 50  0001 C CNN
+	1    3650 1400
+	1    0    0    -1  
+$EndComp
+Wire Wire Line
+	3650 1400 3650 1350
+$Comp
+L Device:R R1
+U 1 1 5F860BAB
+P 3750 2300
+F 0 "R1" H 3820 2346 50  0000 L CNN
+F 1 "56k" H 3820 2255 50  0000 L CNN
+F 2 "Resistors_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P5.08mm_Vertical" V 3680 2300 50  0001 C CNN
+F 3 "~" H 3750 2300 50  0001 C CNN
+	1    3750 2300
+	1    0    0    -1  
+$EndComp
+$Comp
+L Device:R R2
+U 1 1 5F8629E7
+P 3750 2750
+F 0 "R2" H 3820 2796 50  0000 L CNN
+F 1 "24k" H 3820 2705 50  0000 L CNN
+F 2 "Resistors_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P5.08mm_Vertical" V 3680 2750 50  0001 C CNN
+F 3 "~" H 3750 2750 50  0001 C CNN
+	1    3750 2750
+	1    0    0    -1  
+$EndComp
+Wire Wire Line
+	3750 2450 3750 2550
+Wire Wire Line
+	3750 2550 4000 2550
+Wire Wire Line
+	4000 2550 4000 4950
+Connection ~ 3750 2550
+Wire Wire Line
+	3750 2550 3750 2600
+Wire Wire Line
+	4000 4950 6800 4950
+$Comp
+L power:GND #PWR0105
+U 1 1 5F86AB14
+P 3750 3000
+F 0 "#PWR0105" H 3750 2750 50  0001 C CNN
+F 1 "GND" H 3755 2827 50  0000 C CNN
+F 2 "" H 3750 3000 50  0001 C CNN
+F 3 "" H 3750 3000 50  0001 C CNN
+	1    3750 3000
+	1    0    0    -1  
+$EndComp
+Wire Wire Line
+	3750 3000 3750 2900
+$Comp
+L power:+5V #PWR0106
+U 1 1 5F885BEA
+P 4100 850
+F 0 "#PWR0106" H 4100 700 50  0001 C CNN
+F 1 "+5V" H 4115 1023 50  0000 C CNN
+F 2 "" H 4100 850 50  0001 C CNN
+F 3 "" H 4100 850 50  0001 C CNN
+	1    4100 850 
+	1    0    0    -1  
+$EndComp
+Wire Wire Line
+	4100 850  4100 1050
+Wire Wire Line
+	3950 1050 4100 1050
+$Comp
+L Device:CP C2
+U 1 1 5F88AF10
+P 4100 1200
+F 0 "C2" H 4218 1246 50  0000 L CNN
+F 1 "47u" H 4218 1155 50  0000 L CNN
+F 2 "Capacitors_THT:CP_Radial_D5.0mm_P2.50mm" H 4138 1050 50  0001 C CNN
+F 3 "~" H 4100 1200 50  0001 C CNN
+	1    4100 1200
+	1    0    0    -1  
+$EndComp
+Connection ~ 4100 1050
+$Comp
+L power:GND #PWR0107
+U 1 1 5F88BA01
+P 4100 1400
+F 0 "#PWR0107" H 4100 1150 50  0001 C CNN
+F 1 "GND" H 4105 1227 50  0000 C CNN
+F 2 "" H 4100 1400 50  0001 C CNN
+F 3 "" H 4100 1400 50  0001 C CNN
+	1    4100 1400
+	1    0    0    -1  
+$EndComp
+Wire Wire Line
+	4100 1350 4100 1400
+Text Notes 4000 2450 0    35   ~ 0
+Power Good Detection \nfor triggering save to \nEEPROM before buffered \npower supply is out
+Wire Wire Line
+	6800 3750 6800 4950
+Wire Wire Line
+	4350 3650 4600 3650
+Wire Wire Line
+	3750 2150 4600 2150
+Wire Wire Line
+	6700 4750 4350 4750
+Wire Wire Line
+	6800 3750 6500 3750
+Wire Notes Line
+	700  600  7900 600 
+Wire Notes Line
+	7900 600  7900 6300
+Wire Notes Line
+	7900 6300 6350 6300
+Wire Notes Line
+	6350 6300 6350 7100
+Wire Notes Line
+	6350 7100 700  7100
+Wire Notes Line
+	700  7100 700  600 
+Text Notes 800  750  0    50   ~ 0
+Impulse Counter Unit
+Text Notes 7150 7000 0    79   ~ 0
+Dual Impulse Counter \nwith EEPROM persistent storage, Power Fail detection
+$Comp
+L Isolator:PC817 U2
+U 1 1 5F925BDD
+P 2150 3400
+F 0 "U2" H 2150 3725 50  0000 C CNN
+F 1 "PC817" H 2150 3634 50  0000 C CNN
+F 2 "Housings_DIP:DIP-4_W7.62mm" H 1950 3200 50  0001 L CIN
+F 3 "http://www.soselectronic.cz/a_info/resource/d/pc817.pdf" H 2150 3400 50  0001 L CNN
+	1    2150 3400
+	1    0    0    -1  
+$EndComp
+$Comp
+L Connector:Screw_Terminal_01x03 J2
+U 1 1 5F92B88F
+P 1100 3500
+F 0 "J2" H 1018 3817 50  0000 C CNN
+F 1 "IMP_IN_1" H 1018 3726 50  0000 C CNN
+F 2 "Connectors_Terminal_Blocks:TerminalBlock_bornier-3_P5.08mm" H 1100 3500 50  0001 C CNN
+F 3 "~" H 1100 3500 50  0001 C CNN
+	1    1100 3500
+	-1   0    0    1   
+$EndComp
+Wire Wire Line
+	3750 2150 3750 1700
+Connection ~ 3750 2150
+$Comp
+L power:GND #PWR0108
+U 1 1 5F946F37
+P 2450 3600
+F 0 "#PWR0108" H 2450 3350 50  0001 C CNN
+F 1 "GND" H 2455 3427 50  0000 C CNN
+F 2 "" H 2450 3600 50  0001 C CNN
+F 3 "" H 2450 3600 50  0001 C CNN
+	1    2450 3600
+	1    0    0    -1  
+$EndComp
+Wire Wire Line
+	2450 3600 2450 3500
+$Comp
+L Device:R R3
+U 1 1 5F94A6CF
+P 1650 3500
+F 0 "R3" V 1443 3500 50  0000 C CNN
+F 1 "220" V 1534 3500 50  0000 C CNN
+F 2 "Resistors_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P5.08mm_Vertical" V 1580 3500 50  0001 C CNN
+F 3 "~" H 1650 3500 50  0001 C CNN
+	1    1650 3500
+	0    1    1    0   
+$EndComp
+$Comp
+L power:+5V #PWR0109
+U 1 1 5F94CADA
+P 1400 2600
+F 0 "#PWR0109" H 1400 2450 50  0001 C CNN
+F 1 "+5V" H 1415 2773 50  0000 C CNN
+F 2 "" H 1400 2600 50  0001 C CNN
+F 3 "" H 1400 2600 50  0001 C CNN
+	1    1400 2600
+	1    0    0    -1  
+$EndComp
+$Comp
+L Regulator_Linear:L7805 U1
+U 1 1 5F94F630
+P 3650 1050
+F 0 "U1" H 3650 1292 50  0000 C CNN
+F 1 "L7805" H 3650 1201 50  0000 C CNN
+F 2 "TO_SOT_Packages_THT:TO-220-3_Vertical" H 3675 900 50  0001 L CIN
+F 3 "http://www.st.com/content/ccc/resource/technical/document/datasheet/41/4f/b3/b0/12/d4/47/88/CD00000444.pdf/files/CD00000444.pdf/jcr:content/translations/en.CD00000444.pdf" H 3650 1000 50  0001 C CNN
+	1    3650 1050
+	1    0    0    -1  
+$EndComp
+Wire Wire Line
+	1300 3400 1400 3400
+Wire Wire Line
+	1300 3500 1500 3500
+$Comp
+L power:GND #PWR0110
+U 1 1 5F963EDF
+P 1300 3700
+F 0 "#PWR0110" H 1300 3450 50  0001 C CNN
+F 1 "GND" H 1305 3527 50  0000 C CNN
+F 2 "" H 1300 3700 50  0001 C CNN
+F 3 "" H 1300 3700 50  0001 C CNN
+	1    1300 3700
+	1    0    0    -1  
+$EndComp
+Wire Wire Line
+	1300 3600 1300 3700
+Wire Wire Line
+	1850 3500 1800 3500
+Wire Wire Line
+	1850 3300 1850 3200
+Wire Wire Line
+	2450 3300 2700 3300
+$Comp
+L Device:LED D3
+U 1 1 5F983BBB
+P 1650 2650
+F 0 "D3" H 1643 2395 50  0000 C CNN
+F 1 "LED" H 1643 2486 50  0000 C CNN
+F 2 "LEDs:LED_D3.0mm" H 1650 2650 50  0001 C CNN
+F 3 "~" H 1650 2650 50  0001 C CNN
+	1    1650 2650
+	-1   0    0    1   
+$EndComp
+Wire Wire Line
+	1850 3200 1400 3200
+Connection ~ 1400 3200
+Wire Wire Line
+	1400 3200 1400 3400
+$Comp
+L Device:R R4
+U 1 1 5F9A2208
+P 1650 3050
+F 0 "R4" V 1443 3050 50  0000 C CNN
+F 1 "560" V 1534 3050 50  0000 C CNN
+F 2 "Resistors_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P5.08mm_Vertical" V 1580 3050 50  0001 C CNN
+F 3 "~" H 1650 3050 50  0001 C CNN
+	1    1650 3050
+	0    1    1    0   
+$EndComp
+Wire Wire Line
+	1500 3050 1500 3500
+Connection ~ 1500 3500
+$Comp
+L Isolator:PC817 U3
+U 1 1 5F9B7136
+P 2200 5150
+F 0 "U3" H 2200 5475 50  0000 C CNN
+F 1 "PC817" H 2200 5384 50  0000 C CNN
+F 2 "Housings_DIP:DIP-4_W7.62mm" H 2000 4950 50  0001 L CIN
+F 3 "http://www.soselectronic.cz/a_info/resource/d/pc817.pdf" H 2200 5150 50  0001 L CNN
+	1    2200 5150
+	1    0    0    -1  
+$EndComp
+$Comp
+L Connector:Screw_Terminal_01x03 J3
+U 1 1 5F9B713C
+P 1150 5250
+F 0 "J3" H 1068 5567 50  0000 C CNN
+F 1 "IMP_IN_2" H 1068 5476 50  0000 C CNN
+F 2 "Connectors_Terminal_Blocks:TerminalBlock_bornier-3_P5.08mm" H 1150 5250 50  0001 C CNN
+F 3 "~" H 1150 5250 50  0001 C CNN
+	1    1150 5250
+	-1   0    0    1   
+$EndComp
+$Comp
+L power:GND #PWR0111
+U 1 1 5F9B7142
+P 2500 5350
+F 0 "#PWR0111" H 2500 5100 50  0001 C CNN
+F 1 "GND" H 2505 5177 50  0000 C CNN
+F 2 "" H 2500 5350 50  0001 C CNN
+F 3 "" H 2500 5350 50  0001 C CNN
+	1    2500 5350
+	1    0    0    -1  
+$EndComp
+Wire Wire Line
+	2500 5350 2500 5250
+$Comp
+L Device:R R5
+U 1 1 5F9B7149
+P 1700 5250
+F 0 "R5" V 1907 5250 50  0000 C CNN
+F 1 "220" V 1816 5250 50  0000 C CNN
+F 2 "Resistors_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P5.08mm_Vertical" V 1630 5250 50  0001 C CNN
+F 3 "~" H 1700 5250 50  0001 C CNN
+	1    1700 5250
+	0    1    -1   0   
+$EndComp
+$Comp
+L power:+5V #PWR0112
+U 1 1 5F9B714F
+P 1450 4400
+F 0 "#PWR0112" H 1450 4250 50  0001 C CNN
+F 1 "+5V" H 1465 4573 50  0000 C CNN
+F 2 "" H 1450 4400 50  0001 C CNN
+F 3 "" H 1450 4400 50  0001 C CNN
+	1    1450 4400
+	1    0    0    -1  
+$EndComp
+Wire Wire Line
+	1350 5150 1450 5150
+Wire Wire Line
+	1350 5250 1550 5250
+$Comp
+L power:GND #PWR0113
+U 1 1 5F9B7157
+P 1350 5450
+F 0 "#PWR0113" H 1350 5200 50  0001 C CNN
+F 1 "GND" H 1355 5277 50  0000 C CNN
+F 2 "" H 1350 5450 50  0001 C CNN
+F 3 "" H 1350 5450 50  0001 C CNN
+	1    1350 5450
+	1    0    0    -1  
+$EndComp
+Wire Wire Line
+	1350 5350 1350 5450
+Wire Wire Line
+	1900 5250 1850 5250
+Wire Wire Line
+	1900 5050 1900 4950
+Wire Wire Line
+	2500 5050 2750 5050
+$Comp
+L Device:LED D4
+U 1 1 5F9B7161
+P 1700 4400
+F 0 "D4" H 1693 4145 50  0000 C CNN
+F 1 "LED" H 1693 4236 50  0000 C CNN
+F 2 "LEDs:LED_D3.0mm" H 1700 4400 50  0001 C CNN
+F 3 "~" H 1700 4400 50  0001 C CNN
+	1    1700 4400
+	-1   0    0    1   
+$EndComp
+Wire Wire Line
+	1900 4950 1450 4950
+Connection ~ 1450 4950
+Wire Wire Line
+	1450 4950 1450 5150
+$Comp
+L Device:R R6
+U 1 1 5F9B716A
+P 1700 4800
+F 0 "R6" V 1493 4800 50  0000 C CNN
+F 1 "560" V 1584 4800 50  0000 C CNN
+F 2 "Resistors_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P5.08mm_Vertical" V 1630 4800 50  0001 C CNN
+F 3 "~" H 1700 4800 50  0001 C CNN
+	1    1700 4800
+	0    1    1    0   
+$EndComp
+Wire Wire Line
+	1550 4800 1550 5250
+Connection ~ 1550 5250
+Wire Wire Line
+	1550 4650 1450 4650
+Connection ~ 1450 4650
+Wire Wire Line
+	1450 4650 1450 4950
+Wire Wire Line
+	1450 4400 1450 4650
+Wire Wire Line
+	1500 1050 2250 1050
+Text Label 6550 2050 0    50   ~ 0
+MCU_INT0
+Wire Wire Line
+	6550 2050 6500 2050
+Text Label 6550 2150 0    50   ~ 0
+MCU_INT1
+Wire Wire Line
+	6550 2150 6500 2150
+Text Label 2750 5050 0    50   ~ 0
+MCU_INT1
+Text Label 2700 3300 0    50   ~ 0
+MCU_INT0
+Wire Wire Line
+	1550 4400 1550 4650
+Wire Wire Line
+	1850 4400 1850 4800
+Wire Wire Line
+	1800 2650 1800 3050
+Wire Wire Line
+	1500 2900 1400 2900
+Connection ~ 1400 2900
+Wire Wire Line
+	1400 2900 1400 3200
+Wire Wire Line
+	1500 2650 1500 2900
+Wire Wire Line
+	1400 2600 1400 2900
+Text Label 6550 1850 0    50   ~ 0
+MCU_RX
+Wire Wire Line
+	6550 1850 6500 1850
+Text Label 6550 1950 0    50   ~ 0
+MCU_TX
+Wire Wire Line
+	6550 1950 6500 1950
+Wire Wire Line
+	2250 1600 2250 1700
+Wire Wire Line
+	2250 1700 3750 1700
+Connection ~ 2250 1700
+Wire Wire Line
+	2250 1700 2250 1800
+$Comp
+L Diode:1N4001 D2
+U 1 1 5FA7B88E
+P 2650 1050
+F 0 "D2" V 2696 971 50  0000 R CNN
+F 1 "1N4001" V 2605 971 50  0000 R CNN
+F 2 "Diodes_THT:D_DO-41_SOD81_P10.16mm_Horizontal" H 2650 875 50  0001 C CNN
+F 3 "http://www.vishay.com/docs/88503/1n4001.pdf" H 2650 1050 50  0001 C CNN
+	1    2650 1050
+	-1   0    0    1   
+$EndComp
+Wire Wire Line
+	2500 1050 2250 1050
+Connection ~ 2250 1050
+Wire Wire Line
+	2800 1050 3350 1050
+$EndSCHEMATC

+ 21 - 0
Hardware/Schematics/Modules-FloKra.bck

@@ -0,0 +1,21 @@
+EESchema-DOCLIB  Version 2.0
+#
+$CMP ArduinoProMini_2
+D Arduino Pro Mini China variant, ATMEGA328, 16k Flash, 1kB SRAM, 512B EEPROM
+K Arduino Pro Mini China AVR 8bit Microcontroller MegaAVR
+F http://www.arduino.cc/en/uploads/Main/Arduino-Pro-Mini-schematic.pdf
+$ENDCMP
+#
+$CMP ArduinoProMini_allHeaders
+D Arduino Pro Mini China variant, ATMEGA328, 16k Flash, 1kB SRAM, 512B EEPROM
+K Arduino Pro Mini China AVR 8bit Microcontroller MegaAVR
+F http://www.arduino.cc/en/uploads/Main/Arduino-Pro-Mini-schematic.pdf
+$ENDCMP
+#
+$CMP ArduinoProMini_noAddHeaders
+D Arduino Pro Mini China variant, ATMEGA328, 16k Flash, 1kB SRAM, 512B EEPROM
+K Arduino Pro Mini China AVR 8bit Microcontroller MegaAVR
+F http://www.arduino.cc/en/uploads/Main/Arduino-Pro-Mini-schematic.pdf
+$ENDCMP
+#
+#End Doc Library

+ 15 - 0
Hardware/Schematics/Modules-FloKra.dcm

@@ -0,0 +1,15 @@
+EESchema-DOCLIB  Version 2.0
+#
+$CMP ArduinoProMini_allHeaders
+D Arduino Pro Mini China variant, ATMEGA328, 16k Flash, 1kB SRAM, 512B EEPROM
+K Arduino Pro Mini China AVR 8bit Microcontroller MegaAVR
+F http://www.arduino.cc/en/uploads/Main/Arduino-Pro-Mini-schematic.pdf
+$ENDCMP
+#
+$CMP ArduinoProMini_noAddHeaders
+D Arduino Pro Mini China variant, ATMEGA328, 16k Flash, 1kB SRAM, 512B EEPROM
+K Arduino Pro Mini China AVR 8bit Microcontroller MegaAVR
+F http://www.arduino.cc/en/uploads/Main/Arduino-Pro-Mini-schematic.pdf
+$ENDCMP
+#
+#End Doc Library

+ 108 - 0
Hardware/Schematics/Modules-FloKra.lib

@@ -0,0 +1,108 @@
+EESchema-LIBRARY Version 2.4
+#encoding utf-8
+#
+# ArduinoProMini_allHeaders
+#
+DEF ArduinoProMini_allHeaders IC 0 40 Y Y 1 F N
+F0 "IC" -750 1250 40 H V L BNN
+F1 "ArduinoProMini_allHeaders" 400 -1400 40 H V L BNN
+F2 "FloKra-Modules:ArduinoProMini_2" 0 0 30 H I C CIN
+F3 "" 0 0 60 H V C CNN
+$FPLIST
+ pro_mini*
+$ENDFPLIST
+DRAW
+S -750 1200 850 -1300 0 1 10 f
+X (PCINT17/TXD)PD1/1 1 1000 1000 150 L 40 40 1 1 B
+X (PCINT23/AIN1)PD7/7 10 1000 400 150 L 40 40 1 1 B
+X (PCINT0/CLKO/ICP1)PB0/8 11 1000 300 150 L 40 40 1 1 B
+X (PCINT1/OC1A/PWM)PB1/9 12 1000 200 150 L 40 40 1 1 B
+X (PCINT2/OC1B/~SS~/PWM)PB2/10 13 1000 100 150 L 40 40 1 1 B
+X (PCINT3/OC2A/MOSI/PWM)PB3/11 14 1000 -100 150 L 40 40 1 1 B
+X (PCINT4/MISO)PB4/12 15 1000 -200 150 L 40 40 1 1 B
+X (PCINT5/SCK)PB5/13 16 1000 -300 150 L 40 40 1 1 B
+X (PCINT8/ADC0)PC0/14/A0 17 1000 -500 150 L 40 40 1 1 B
+X (PCINT9/ADC1)PC1/15/A1 18 1000 -600 150 L 40 40 1 1 B
+X (PCINT10/ADC2)PC2/16/A2 19 1000 -700 150 L 40 40 1 1 B
+X (PCINT16/RXD)PD0/0 2 1000 1100 150 L 40 40 1 1 B
+X (PCINT11/ADC3)PC3/17/A3 20 1000 -800 150 L 40 40 1 1 B
+X VCC 21 -900 1100 150 R 40 40 1 1 W
+X (PCINT14/~RESET~)PC6 22 -900 -800 150 R 40 40 1 1 B
+X GND 23 -900 -1100 150 R 40 40 1 1 W
+X RAW 24 -900 800 150 R 40 40 1 1 W
+X (PCINT12/SDA/ADC4)PC4/18/A4 25 1000 -900 150 L 40 40 1 1 B
+X (PCINT13/SCL/ADC5)PC5/19/A5 26 1000 -1000 150 L 40 40 1 1 B
+X ADC6/A6 27 1000 -1100 150 L 40 40 1 1 I
+X ADC7/A7 28 1000 -1200 150 L 40 40 1 1 I
+X GND 29 -900 -1200 150 R 40 40 1 1 W
+X (PCINT14/~RESET~)PC6 3 -900 -700 150 R 40 40 1 1 B
+X DTR 30 -150 1400 200 D 50 50 1 1 I
+X GND 4 -900 -1000 150 R 40 40 1 1 W
+X (PCINT18/INT0)PD2/2 5 1000 900 150 L 40 40 1 1 B
+X (PCINT19/OC2B/INT1/PWM)PD3/3 6 1000 800 150 L 40 40 1 1 B
+X (PCINT20/XCK/T0)PD4/4 7 1000 700 150 L 40 40 1 1 B
+X (PCINT21/OC0B/T1/PWM)PD5/5 8 1000 600 150 L 40 40 1 1 B
+X (PCINT22/OC0A/AIN0/PWM)PD6/6 9 1000 500 150 L 40 40 1 1 B
+ENDDRAW
+ENDDEF
+#
+# ArduinoProMini_noAddHeaders
+#
+DEF ArduinoProMini_noAddHeaders IC 0 40 Y Y 1 F N
+F0 "IC" -750 1250 40 H V L BNN
+F1 "ArduinoProMini_noAddHeaders" 400 -1400 40 H V L BNN
+F2 "FloKra-Modules:ArduinoProMini_2" 0 0 30 H I C CIN
+F3 "" 0 0 60 H V C CNN
+$FPLIST
+ pro_mini*
+$ENDFPLIST
+DRAW
+S -750 1200 850 -1300 0 1 10 f
+X (PCINT17/TXD)PD1/1 1 1000 1000 150 L 40 40 1 1 B
+X (PCINT23/AIN1)PD7/7 10 1000 400 150 L 40 40 1 1 B
+X (PCINT0/CLKO/ICP1)PB0/8 11 1000 300 150 L 40 40 1 1 B
+X (PCINT1/OC1A/PWM)PB1/9 12 1000 200 150 L 40 40 1 1 B
+X (PCINT2/OC1B/~SS~/PWM)PB2/10 13 1000 100 150 L 40 40 1 1 B
+X (PCINT3/OC2A/MOSI/PWM)PB3/11 14 1000 -100 150 L 40 40 1 1 B
+X (PCINT4/MISO)PB4/12 15 1000 -200 150 L 40 40 1 1 B
+X (PCINT5/SCK)PB5/13 16 1000 -300 150 L 40 40 1 1 B
+X (PCINT8/ADC0)PC0/14/A0 17 1000 -500 150 L 40 40 1 1 B
+X (PCINT9/ADC1)PC1/15/A1 18 1000 -600 150 L 40 40 1 1 B
+X (PCINT10/ADC2)PC2/16/A2 19 1000 -700 150 L 40 40 1 1 B
+X (PCINT16/RXD)PD0/0 2 1000 1100 150 L 40 40 1 1 B
+X (PCINT11/ADC3)PC3/17/A3 20 1000 -800 150 L 40 40 1 1 B
+X VCC 21 -900 1100 150 R 40 40 1 1 W
+X (PCINT14/~RESET~)PC6 22 -900 -800 150 R 40 40 1 1 B
+X GND 23 -900 -1100 150 R 40 40 1 1 W
+X RAW 24 -900 800 150 R 40 40 1 1 W
+X (PCINT14/~RESET~)PC6 3 -900 -700 150 R 40 40 1 1 B
+X GND 4 -900 -1000 150 R 40 40 1 1 W
+X (PCINT18/INT0)PD2/2 5 1000 900 150 L 40 40 1 1 B
+X (PCINT19/OC2B/INT1/PWM)PD3/3 6 1000 800 150 L 40 40 1 1 B
+X (PCINT20/XCK/T0)PD4/4 7 1000 700 150 L 40 40 1 1 B
+X (PCINT21/OC0B/T1/PWM)PD5/5 8 1000 600 150 L 40 40 1 1 B
+X (PCINT22/OC0A/AIN0/PWM)PD6/6 9 1000 500 150 L 40 40 1 1 B
+ENDDRAW
+ENDDEF
+#
+# RS232<->TTL
+#
+DEF RS232<->TTL U 0 40 Y Y 1 F N
+F0 "U" 0 0 50 H V C CNN
+F1 "RS232<->TTL" 200 -250 50 H V C CNN
+F2 "" 0 0 50 H I C CNN
+F3 "" 0 0 50 H I C CNN
+DRAW
+S -200 -50 600 -550 0 1 0 N
+X < ~ -400 -100 200 R 50 50 1 1 O
+X < ~ 800 -400 200 L 50 50 1 1 I
+X > ~ -400 -200 200 R 50 50 1 1 I
+X > ~ 800 -500 200 L 50 50 1 1 O
+X GND ~ -400 -500 200 R 50 50 1 1 W
+X GND ~ 800 -200 200 L 50 50 1 1 W
+X Vcc ~ -400 -400 200 R 50 50 1 1 W
+X Vcc ~ 800 -100 200 L 50 50 1 1 W
+ENDDRAW
+ENDDEF
+#
+#End Library

+ 463 - 0
Hardware/Schematics/fp-info-cache

@@ -0,0 +1,463 @@
+1603378568935
+Diodes_THT
+D_5KPW_P7.62mm_Vertical_AnodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_5KPW_P7.62mm_Vertical_KathodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_5KPW_P12.70mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_5KP_P7.62mm_Vertical_AnodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_5KP_P7.62mm_Vertical_KathodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_5KP_P10.16mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_5KP_P12.70mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_5W_P5.08mm_Vertical_AnodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_5W_P5.08mm_Vertical_KathodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_5W_P10.16mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_5W_P12.70mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_A-405_P2.54mm_Vertical_AnodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_A-405_P2.54mm_Vertical_KathodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_A-405_P5.08mm_Vertical_AnodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_A-405_P5.08mm_Vertical_KathodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_A-405_P7.62mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_A-405_P10.16mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_A-405_P12.70mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_DO-15_P2.54mm_Vertical_AnodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-15_P2.54mm_Vertical_KathodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-15_P5.08mm_Vertical_AnodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-15_P5.08mm_Vertical_KathodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-15_P10.16mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_DO-15_P12.70mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_DO-15_P15.24mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_DO-27_P5.08mm_Vertical_AnodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-27_P5.08mm_Vertical_KathodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-27_P12.70mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_DO-27_P15.24mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_DO-35_SOD27_P2.54mm_Vertical_AnodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-35_SOD27_P2.54mm_Vertical_KathodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-35_SOD27_P5.08mm_Vertical_AnodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-35_SOD27_P5.08mm_Vertical_KathodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-35_SOD27_P7.62mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_DO-35_SOD27_P10.16mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_DO-35_SOD27_P12.70mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_DO-41_SOD81_P2.54mm_Vertical_AnodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-41_SOD81_P2.54mm_Vertical_KathodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-41_SOD81_P5.08mm_Vertical_AnodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-41_SOD81_P5.08mm_Vertical_KathodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-41_SOD81_P7.62mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_DO-41_SOD81_P10.16mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_DO-41_SOD81_P12.70mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_DO-201AD_P5.08mm_Vertical_AnodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-201AD_P5.08mm_Vertical_KathodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-201AD_P12.70mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_DO-201AD_P15.24mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_DO-201_P5.08mm_Vertical_AnodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-201_P5.08mm_Vertical_KathodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_DO-201_P12.70mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_DO-201_P15.24mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_P600_R-6_P7.62mm_Vertical_AnodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_P600_R-6_P7.62mm_Vertical_KathodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_P600_R-6_P12.70mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_P600_R-6_P20.00mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_T-1_P2.54mm_Vertical_AnodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_T-1_P2.54mm_Vertical_KathodeUp
+
+
+0
+0
+0
+Diodes_THT
+D_T-1_P5.08mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_T-1_P10.16mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+D_T-1_P12.70mm_Horizontal
+
+
+0
+0
+0
+Diodes_THT
+Diode_Bridge_15.7x15.7
+
+
+0
+0
+0
+Diodes_THT
+Diode_Bridge_16.7x16.7
+
+
+0
+0
+0
+Diodes_THT
+Diode_Bridge_18.5x5.5
+
+
+0
+0
+0
+Diodes_THT
+Diode_Bridge_DIP-4_W7.62mm_P5.08mm
+
+
+0
+0
+0
+Diodes_THT
+Diode_Bridge_Round_D8.9mm
+
+
+0
+0
+0
+Diodes_THT
+Diode_Bridge_Round_D9.8mm
+
+
+0
+0
+0

+ 3 - 0
Hardware/Schematics/fp-lib-table

@@ -0,0 +1,3 @@
+(fp_lib_table
+  (lib (name FloKra_Modules)(type KiCad)(uri ${KIPRJMOD}/FloKra_Modules.pretty)(options "")(descr ""))
+)

BIN
NodeRED-UI/NodeRED_UI.png


+ 612 - 0
NodeRED-UI/NodeRED_flow.json

@@ -0,0 +1,612 @@
+[
+    {
+        "id": "49762a14.53df54",
+        "type": "tab",
+        "label": "S0Meters",
+        "disabled": false,
+        "info": ""
+    },
+    {
+        "id": "231ba654.08ce1a",
+        "type": "ui_text_input",
+        "z": "49762a14.53df54",
+        "name": "",
+        "label": "set new reading",
+        "group": "5cdd7758.149278",
+        "order": 2,
+        "width": 0,
+        "height": 0,
+        "passthru": false,
+        "mode": "text",
+        "delay": "300",
+        "topic": "",
+        "x": 540,
+        "y": 140,
+        "wires": [
+            [
+                "4a109952.f06e48"
+            ]
+        ]
+    },
+    {
+        "id": "1ca1176d.d5c471",
+        "type": "ui_text",
+        "z": "49762a14.53df54",
+        "group": "5cdd7758.149278",
+        "order": 1,
+        "width": 0,
+        "height": 0,
+        "name": "",
+        "label": "current reading",
+        "format": "{{msg.payload}}",
+        "layout": "row-spread",
+        "x": 540,
+        "y": 100,
+        "wires": []
+    },
+    {
+        "id": "74e1dc04.2d60a4",
+        "type": "mqtt in",
+        "z": "49762a14.53df54",
+        "name": "",
+        "topic": "T5/Zaehler/Strom/reading",
+        "qos": "2",
+        "datatype": "auto",
+        "broker": "594053fb.ec274c",
+        "x": 300,
+        "y": 100,
+        "wires": [
+            [
+                "1ca1176d.d5c471"
+            ]
+        ]
+    },
+    {
+        "id": "4a109952.f06e48",
+        "type": "function",
+        "z": "49762a14.53df54",
+        "name": "",
+        "func": "flow.set(\"stromz_newReading\", msg.payload, \"memoryOnly\");\nreturn msg;",
+        "outputs": 1,
+        "noerr": 0,
+        "initialize": "",
+        "finalize": "",
+        "x": 760,
+        "y": 140,
+        "wires": [
+            [
+                "6aa2d3.79145d2c"
+            ]
+        ]
+    },
+    {
+        "id": "6aa2d3.79145d2c",
+        "type": "debug",
+        "z": "49762a14.53df54",
+        "name": "",
+        "active": false,
+        "tosidebar": true,
+        "console": false,
+        "tostatus": false,
+        "complete": "false",
+        "statusVal": "",
+        "statusType": "auto",
+        "x": 970,
+        "y": 140,
+        "wires": []
+    },
+    {
+        "id": "7e3160e.661e0a",
+        "type": "ui_button",
+        "z": "49762a14.53df54",
+        "name": "",
+        "group": "5cdd7758.149278",
+        "order": 3,
+        "width": 0,
+        "height": 0,
+        "passthru": false,
+        "label": "WRITE TO HARDWARE",
+        "tooltip": "",
+        "color": "",
+        "bgcolor": "",
+        "icon": "",
+        "payload": "",
+        "payloadType": "str",
+        "topic": "",
+        "x": 570,
+        "y": 180,
+        "wires": [
+            [
+                "98434a49.bbb93",
+                "7eff858e.4161b4"
+            ]
+        ]
+    },
+    {
+        "id": "98434a49.bbb93",
+        "type": "function",
+        "z": "49762a14.53df54",
+        "name": "",
+        "func": "newReading = flow.get(\"stromz_newReading\", \"memoryOnly\")||undefined;\nif (newReading !== undefined && !isNaN(newReading)) {\n    newReading = parseFloat(newReading).toFixed(3);\n    msg.payload = \"set reading c1 \" + newReading;\n    return msg;\n}",
+        "outputs": 1,
+        "noerr": 0,
+        "initialize": "",
+        "finalize": "",
+        "x": 760,
+        "y": 180,
+        "wires": [
+            [
+                "88f97e0e.83b77",
+                "6a2c0078.8cc4e8"
+            ]
+        ]
+    },
+    {
+        "id": "88f97e0e.83b77",
+        "type": "debug",
+        "z": "49762a14.53df54",
+        "name": "",
+        "active": false,
+        "tosidebar": true,
+        "console": false,
+        "tostatus": false,
+        "complete": "false",
+        "statusVal": "",
+        "statusType": "auto",
+        "x": 970,
+        "y": 180,
+        "wires": []
+    },
+    {
+        "id": "1d4a3586.9f37f2",
+        "type": "ui_text_input",
+        "z": "49762a14.53df54",
+        "name": "",
+        "label": "set new reading",
+        "tooltip": "",
+        "group": "2edae4eb.ff06bc",
+        "order": 2,
+        "width": 0,
+        "height": 0,
+        "passthru": false,
+        "mode": "text",
+        "delay": "300",
+        "topic": "",
+        "x": 540,
+        "y": 320,
+        "wires": [
+            [
+                "b8760526.dcc028"
+            ]
+        ]
+    },
+    {
+        "id": "a298d89b.0734b",
+        "type": "ui_text",
+        "z": "49762a14.53df54",
+        "group": "2edae4eb.ff06bc",
+        "order": 1,
+        "width": 0,
+        "height": 0,
+        "name": "",
+        "label": "current reading",
+        "format": "{{msg.payload}}",
+        "layout": "row-spread",
+        "x": 540,
+        "y": 280,
+        "wires": []
+    },
+    {
+        "id": "49d5ee8f.e41a48",
+        "type": "mqtt in",
+        "z": "49762a14.53df54",
+        "name": "",
+        "topic": "T5/Zaehler/Gas/reading",
+        "qos": "2",
+        "datatype": "auto",
+        "broker": "594053fb.ec274c",
+        "x": 290,
+        "y": 280,
+        "wires": [
+            [
+                "a298d89b.0734b"
+            ]
+        ]
+    },
+    {
+        "id": "b8760526.dcc028",
+        "type": "function",
+        "z": "49762a14.53df54",
+        "name": "",
+        "func": "flow.set(\"gasz_newReading\", msg.payload, \"memoryOnly\");\nreturn msg;",
+        "outputs": 1,
+        "noerr": 0,
+        "initialize": "",
+        "finalize": "",
+        "x": 760,
+        "y": 320,
+        "wires": [
+            [
+                "9733c14a.9ce9e8"
+            ]
+        ]
+    },
+    {
+        "id": "9733c14a.9ce9e8",
+        "type": "debug",
+        "z": "49762a14.53df54",
+        "name": "",
+        "active": false,
+        "tosidebar": true,
+        "console": false,
+        "tostatus": false,
+        "complete": "false",
+        "statusVal": "",
+        "statusType": "auto",
+        "x": 970,
+        "y": 320,
+        "wires": []
+    },
+    {
+        "id": "8e6da1ad.d04a3",
+        "type": "ui_button",
+        "z": "49762a14.53df54",
+        "name": "",
+        "group": "2edae4eb.ff06bc",
+        "order": 3,
+        "width": 0,
+        "height": 0,
+        "passthru": false,
+        "label": "WRITE TO HARDWARE",
+        "tooltip": "",
+        "color": "",
+        "bgcolor": "",
+        "icon": "",
+        "payload": "",
+        "payloadType": "str",
+        "topic": "",
+        "x": 570,
+        "y": 360,
+        "wires": [
+            [
+                "4da8d6f3.5d40c",
+                "a8906b04.8cd618"
+            ]
+        ]
+    },
+    {
+        "id": "4da8d6f3.5d40c",
+        "type": "function",
+        "z": "49762a14.53df54",
+        "name": "",
+        "func": "newReading = flow.get(\"gasz_newReading\", \"memoryOnly\")||undefined;\nif (newReading !== undefined && !isNaN(newReading)) {\n    newReading = parseFloat(newReading).toFixed(2);\n    msg.payload = \"set reading c2 \" + newReading;\n    return msg;\n}",
+        "outputs": 1,
+        "noerr": 0,
+        "initialize": "",
+        "finalize": "",
+        "x": 760,
+        "y": 360,
+        "wires": [
+            [
+                "88add0c1.5051a",
+                "6a2c0078.8cc4e8"
+            ]
+        ]
+    },
+    {
+        "id": "88add0c1.5051a",
+        "type": "debug",
+        "z": "49762a14.53df54",
+        "name": "",
+        "active": false,
+        "tosidebar": true,
+        "console": false,
+        "tostatus": false,
+        "complete": "false",
+        "statusVal": "",
+        "statusType": "auto",
+        "x": 970,
+        "y": 360,
+        "wires": []
+    },
+    {
+        "id": "87a202e7.90692",
+        "type": "ui_button",
+        "z": "49762a14.53df54",
+        "name": "",
+        "group": "934e6f58.6bd9e8",
+        "order": 3,
+        "width": 0,
+        "height": 0,
+        "passthru": false,
+        "label": "get readings",
+        "tooltip": "",
+        "color": "",
+        "bgcolor": "",
+        "icon": "",
+        "payload": "",
+        "payloadType": "str",
+        "topic": "",
+        "x": 530,
+        "y": 460,
+        "wires": [
+            [
+                "ef18d5b.2d45ea8"
+            ]
+        ]
+    },
+    {
+        "id": "ef18d5b.2d45ea8",
+        "type": "function",
+        "z": "49762a14.53df54",
+        "name": "",
+        "func": "msg.payload = \"get readings\";\nreturn msg;\n",
+        "outputs": 1,
+        "noerr": 0,
+        "initialize": "",
+        "finalize": "",
+        "x": 760,
+        "y": 460,
+        "wires": [
+            [
+                "6a2c0078.8cc4e8"
+            ]
+        ]
+    },
+    {
+        "id": "6a2c0078.8cc4e8",
+        "type": "mqtt out",
+        "z": "49762a14.53df54",
+        "name": "",
+        "topic": "Top5/ImpCount/cmd",
+        "qos": "",
+        "retain": "",
+        "broker": "594053fb.ec274c",
+        "x": 1170,
+        "y": 440,
+        "wires": []
+    },
+    {
+        "id": "a8906b04.8cd618",
+        "type": "function",
+        "z": "49762a14.53df54",
+        "name": "clear",
+        "func": "msg.payload=\"\";\nreturn msg;",
+        "outputs": 1,
+        "noerr": 0,
+        "initialize": "",
+        "finalize": "",
+        "x": 610,
+        "y": 400,
+        "wires": [
+            [
+                "1d4a3586.9f37f2"
+            ]
+        ]
+    },
+    {
+        "id": "7eff858e.4161b4",
+        "type": "function",
+        "z": "49762a14.53df54",
+        "name": "clear",
+        "func": "msg.payload=\"\";\nreturn msg;",
+        "outputs": 1,
+        "noerr": 0,
+        "initialize": "",
+        "finalize": "",
+        "x": 610,
+        "y": 220,
+        "wires": [
+            [
+                "231ba654.08ce1a"
+            ]
+        ]
+    },
+    {
+        "id": "c3d72895.bfc2",
+        "type": "ui_button",
+        "z": "49762a14.53df54",
+        "name": "",
+        "group": "2edae4eb.ff06bc",
+        "order": 3,
+        "width": 0,
+        "height": 0,
+        "passthru": false,
+        "label": "CANCEL",
+        "tooltip": "",
+        "color": "",
+        "bgcolor": "",
+        "icon": "",
+        "payload": "",
+        "payloadType": "str",
+        "topic": "",
+        "x": 460,
+        "y": 400,
+        "wires": [
+            [
+                "a8906b04.8cd618"
+            ]
+        ]
+    },
+    {
+        "id": "a366ae9a.534ec8",
+        "type": "ui_button",
+        "z": "49762a14.53df54",
+        "name": "",
+        "group": "5cdd7758.149278",
+        "order": 3,
+        "width": 0,
+        "height": 0,
+        "passthru": false,
+        "label": "CANCEL",
+        "tooltip": "",
+        "color": "",
+        "bgcolor": "",
+        "icon": "",
+        "payload": "",
+        "payloadType": "str",
+        "topic": "",
+        "x": 460,
+        "y": 220,
+        "wires": [
+            [
+                "7eff858e.4161b4"
+            ]
+        ]
+    },
+    {
+        "id": "caee5194.1dd538",
+        "type": "ui_button",
+        "z": "49762a14.53df54",
+        "name": "",
+        "group": "934e6f58.6bd9e8",
+        "order": 3,
+        "width": 0,
+        "height": 0,
+        "passthru": false,
+        "label": "get counters config",
+        "tooltip": "",
+        "color": "",
+        "bgcolor": "",
+        "icon": "",
+        "payload": "",
+        "payloadType": "str",
+        "topic": "",
+        "x": 550,
+        "y": 520,
+        "wires": [
+            [
+                "d89d0bb6.ac3428"
+            ]
+        ]
+    },
+    {
+        "id": "d89d0bb6.ac3428",
+        "type": "function",
+        "z": "49762a14.53df54",
+        "name": "",
+        "func": "msg.payload = \"get conf\";\nreturn msg;\n",
+        "outputs": 1,
+        "noerr": 0,
+        "initialize": "",
+        "finalize": "",
+        "x": 760,
+        "y": 520,
+        "wires": [
+            [
+                "6a2c0078.8cc4e8"
+            ]
+        ]
+    },
+    {
+        "id": "c8dafb7.0a5c988",
+        "type": "mqtt in",
+        "z": "49762a14.53df54",
+        "name": "",
+        "topic": "Top5/ImpCount/stat",
+        "qos": "2",
+        "datatype": "auto",
+        "broker": "594053fb.ec274c",
+        "x": 290,
+        "y": 600,
+        "wires": [
+            [
+                "badc2da1.db2fc8"
+            ]
+        ]
+    },
+    {
+        "id": "badc2da1.db2fc8",
+        "type": "function",
+        "z": "49762a14.53df54",
+        "name": "",
+        "func": "var tmpstr;\nvar hasData = false;\n\nvar paramsarray;\nvar params;\nvar nameValue;\n\nvar data = {};\n\nif(msg.payload.startsWith('CONF GLOB: ')) {\n    //CONF GLOB: debuglevel=0, debounce=10, debRecov=70, pwrGood=500\n    tmpstr = msg.payload.replace('CONF GLOB: ', '');\n    data.glob = params;\n    hasData = true;\n}\nelse if(msg.payload.startsWith('CONF C1: ')) {\n    //CONF C1: impPerUnit=1000, noImpTout=60, saveInt=30\n    tmpstr = msg.payload.replace('CONF C1: ', '');\n    data.c1 = params;\n    hasData = true;\n}\nelse if(msg.payload.startsWith('CONF C2: ')) {\n    //CONF C2: impPerUnit=100, noImpTout=900, saveInt=60\n    tmpstr = msg.payload.replace('CONF C2: ', '');\n    data.c2 = params;\n    hasData = true;\n}\n\nif (hasData) {\n    tmpstr = tmpstr.replace(/ /g, '');\n    paramsarray = tmpstr.split(',');\n    params = {};\n    for(i=0; i < paramsarray.length; i++) {\n        nameValue = paramsarray[i].split('=');\n        params[nameValue[0]] = nameValue[1];\n    }\n    msg.payload = params;\n    return msg;\n}",
+        "outputs": 1,
+        "noerr": 0,
+        "initialize": "",
+        "finalize": "",
+        "x": 520,
+        "y": 600,
+        "wires": [
+            [
+                "50095636.7885c8"
+            ]
+        ]
+    },
+    {
+        "id": "50095636.7885c8",
+        "type": "debug",
+        "z": "49762a14.53df54",
+        "name": "",
+        "active": true,
+        "tosidebar": true,
+        "console": false,
+        "tostatus": false,
+        "complete": "false",
+        "statusVal": "",
+        "statusType": "auto",
+        "x": 780,
+        "y": 620,
+        "wires": []
+    },
+    {
+        "id": "5cdd7758.149278",
+        "type": "ui_group",
+        "name": "Stromzähler",
+        "tab": "635047a7.d277a8",
+        "order": 2,
+        "disp": true,
+        "width": "6",
+        "collapse": false
+    },
+    {
+        "id": "594053fb.ec274c",
+        "type": "mqtt-broker",
+        "name": "",
+        "broker": "127.0.0.1",
+        "port": "1883",
+        "clientid": "",
+        "usetls": false,
+        "compatmode": true,
+        "keepalive": "15",
+        "cleansession": true,
+        "birthTopic": "NodeRED/LWT",
+        "birthQos": "1",
+        "birthRetain": "true",
+        "birthPayload": "Online",
+        "closeTopic": "NodeRED/LWT",
+        "closeQos": "1",
+        "closeRetain": "true",
+        "closePayload": "Offline",
+        "willTopic": "NodeRED/LWT",
+        "willQos": "0",
+        "willRetain": "true",
+        "willPayload": "Offline"
+    },
+    {
+        "id": "2edae4eb.ff06bc",
+        "type": "ui_group",
+        "name": "Gaszähler",
+        "tab": "635047a7.d277a8",
+        "order": 3,
+        "disp": true,
+        "width": "6",
+        "collapse": false
+    },
+    {
+        "id": "934e6f58.6bd9e8",
+        "type": "ui_group",
+        "name": "Default",
+        "tab": "635047a7.d277a8",
+        "order": 1,
+        "disp": true,
+        "width": "6",
+        "collapse": false
+    },
+    {
+        "id": "635047a7.d277a8",
+        "type": "ui_tab",
+        "name": "StromGasZähler",
+        "icon": "dashboard"
+    }
+]

BIN
NodeRED-UI/NodeRED_flow.png


+ 15 - 0
NodeRED-UI/README.md

@@ -0,0 +1,15 @@
+# S0ImpulseCounter
+
+### Node-RED UI
+
+Straightforward Node-RED flow providing a simple UI to set current readings. 
+
+Connects to "middleware" S0Meters.py over MQTT. 
+
+This can be used to set the current readings from a smartphone after installation or on re-calibration if the values are off. 
+
+![](NodeRED_UI.png)
+
+
+
+![](NodeRED_flow.png)

+ 66 - 0
Notes/Arduino_Impulszaehler_DE.txt

@@ -0,0 +1,66 @@
+Dual Impulse Counter
+
+Grundfunktionen
+ - 2 konfigurierbare Impulszähler für S0-Impulse
+ - derzeit unterstützte Impulse pro Einheit: 10, 100, 1000
+ - Zählung in Ganzzahl-Einheit + Zwischenimpulse
+ - alle Daten werden regelmäßig auf EEPROM gespeichert (Ringspeicher, konfigurierbare Intervalle)
+ - Power-Loss-Detection mit Speicherung der aktuellen Zählerstände
+ - UART-Interface für Daten und Konfiguration
+ - Ausgabe von Zählerstand und Zeit seit dem letzten Impuls
+ - vorgesehen für Einsatz zusammen mit einem Raspberry Pi, mit zugehörigem Datenerfassungsprogramm (Python-Script)
+ - Grund für die Entwicklung war der wenig zuverlässige direkte Einsatz des Raspberry Pi mit Impulszählung über GPIO. 
+   Dabei wurden (mit Python) oft nicht existente Impulse gezählt. Außerdem läuft dieser Zähler dann nur solange der RasPi läuft. 
+   Dieses Projekt wurde entwickelt um in Zukunft nicht mehr ständig die Zählerstände am RasPi mit denen an den echten Zählern abgleichen zu müssen. 
+
+
+Hardware:
+ - Basis ist ein Arduino Pro Mini Clone (ATMega 328p)
+ - Stromversorgung über eigenes Steckernetzteil, 12VDC
+ - Pufferkondensator und Spannungsüberwachung on-board
+ - 2 S0-Impulseingänge mit Optokopplern, active LOW (kompatibel zu S0 Open Collector Ausgängen)
+ - direkte Anbindung über UART an die Zentrale (Raspberry Pi, via USB-UART-Adapter, jedoch OHNE Stromversorgung über USB!!!)
+ - Verbindung der RS232-DTS-Leitung ENTFÄLLT, da diese bei jeder Verbindung einen Reset auslöst. 
+   Um dennoch einen Reset (auch für Firmwareupdate) auslösen zu können ist eine eigene Funktion implementiert. 
+   Hierbei wird jedoch vorher der aktuelle Zählerstand gespeichert. 
+
+Software:
+- direkte Implementierung der Zähler am ATMega - somit wird der Zählerstand auch aktualisiert, wenn RasPi und/oder Ausleseprogramm nicht läuft. 
+  (das war in der Vergangenheit öfters ein Problem)
+  - je Eingang ein Zähler mit konfigurierbaren Parametern: 
+    - Impulszähler mit konfigurierbarer Impulsanzahl pro Einheit (z.B. Gaszähler: 100 Imp/1 m³, Stromzähler: 1000 Imp/kWh)
+	- Einheitenzähler, der bei Überlauf des Impulszählers inkrementiert wird
+	- regelmäßige Speicherung des tatsächlichen Zählerstands im EEPROM
+	  -> Speicherung Einheitenzähler:
+	    - bei jeder Änderung
+		  -> z.B. Gaszähler, 500 m³/Werte pro Jahr => rechnerische Lebensdauer des EEPROM 200 Jahre, 
+		     abgesehen davon, dass der 5 stellige Gaszähler bestimmt nie bis zum Überlauf zählen wird
+		  -> z.B. Stromzähler, 4000 kWh pro Jahr => immer noch 25 Jahre bis zur Erreichung der 100.000 Schreibzyklen des EEPROM
+      - zur Sicherheit gegen fehlerhaft geschriebene Werte, zB. wegen Stromausfall während des Schreibens:
+        - Einheitenzähler wird in 3 verschiedene EEPROM-Adressen gespeichert - Einlesen aller 3 Werte beim Start und Plausibilitätsprüfung
+		- Impulszähler - hier wird zuerst der Wert und dann der write counter (zur Wiederauffindung des letzten Werts nötig) geschrieben. 
+		  Schlägt letzteres fehl gilt automatisch der letzte gespeicherte Wert davor. 
+	  - Speicherung Impulszähler: 
+	    -> höhere Schreiblast als die Einheitenzähler
+	    - Ringspeicher-Methode mir write counter zur Schreiblastverteilung
+        - Speicherung in: 		
+		  - konfigurierbaren fixen Intervallen
+		  - nachdem für ein festlegbares timeout kein neuer Impuls eingegangen ist (beim Gaszähler am sinnvollsten)
+
+
+Befehle: 
+
+
+
+Konfiguration:
+
+set conf c1 impPerUnit=1000
+set conf c1 noImpTout=60
+set conf c1 saveInt=15
+
+or as batch: 
+set conf c1 impperunit=1000;noimptout=60;saveint=15
+set conf c2 impperunit=100;noimptout=60;saveint=15
+	noImpTout => in sekunden
+	saveInt => in minuten
+

+ 54 - 0
README.md

@@ -0,0 +1,54 @@
+# S0ImpulseCounter
+
+Impulse Counter for keeping track of the current reading of power and gas meters with S0 impulse output. 
+
+Consists of Arduino based hardware for capturing impulses and saving the current reading in EEPROM and a Python program to log the data to InfluxDB and publish via MQTT. Also measures duration between impulses, to calculate power/current usage from that. 
+
+Intended to run (but not limited to) on a Raspberry Pi. 
+I developed this project because directly logging impulse counters with the Raspberry Pi using GPIO inputs proved to be unreliable. I experienced missed impulses because the Pi was not running all the time, ghost impulses I don´t know why, even when always using optocouplers on the impulse inputs, and also other issues. 
+So I decided to develop a hardware based impulse capturing module which also saves everything to EEPROM and makes losing of the total values unlikely in the future. Also this module should provide an accurate (well, relatively) measured time between impulses, in order to calculate current power or momentary usage. 
+
+The Arduino based impulse capturing unit counts impulses, increments a counter in a unit like kWh, saves this counter to EEPROM on change, and also saves impulses in between to EEPROM regularly. 
+Impulses count is saved to a large EEPROM area organized as a ring buffer to accomplish little EEPROM wear. 
+
+Regarding the power supply there is buffer capacitor as well as a power loss detection, so that the current values can be saved to EEPROM just before power goes out. 
+Apart from that, saving is performed in configurable intervals and when there was no impulse detected for a timeout (useful for gas counters). 
+
+### Arduino (ATmega) based counter module "DualS0ImpulseCounter"
+- 2 individual inputs/counters with configurable impulses per unit
+- unit-counter is saved to EEPROM on every change
+- impulses in between are saved in configurable intervals
+- impulses counter is saved in a large ring buffer with automatic rollover to minimize EEPROM wear
+- power out detection and saving of all data before power is really gone
+- UART interface to Server/Raspberry/PC, where the actual data logging is done
+- no Arduino-like UART interface with DTS line connected (which resets the Arduino) - instead there is a software function to reset for a firmware update, and just connecting to the UART from the host does NOT reset the device. Scripts to perform Arduino/AVR firmware update from a Raspberry Pi included. 
+
+Details: [Arduino counter hardware](Hardware/)
+
+
+
+### S0Meters (Python program)
+
+- receives data from the module via UART
+- data logging, implemented in 2 manners:
+  - InfluxDB (current total reading, momentary power/usage)
+  - file log (only daily minimum and total value)
+- MQTT publishing of current values
+- calculation of momentary power/usage based on time between impulses received from capturing module
+- calculation of today´s/yesterday´s total usage (only if file logging is enabled)
+- send commands to the module over MQTT (to set readings, configuration, etc.)
+
+Details: [Python S0Meters](S0Meters_py/)
+
+
+
+### Node-RED UI
+
+Straightforward Node-RED flow providing a simple UI to set current readings. 
+
+Connects to "middleware" S0Meters.py over MQTT. 
+
+Details: [NodeRED-UI](NodeRED-UI/)
+
+
+

+ 264 - 0
S0Meters_py/README.md

@@ -0,0 +1,264 @@
+# S0Meters
+
+Python program for logging data captured by ***DualImpCount*** (Arduino based S0 impulse counter module). 
+
+Intended to run (but not limited to) on a Raspberry Pi. 
+
+I developed this plus the hardware counter module because directly logging impulse counters with the Raspberry Pi 
+was not reliable enough for me. Missed impulses, because the Pi was not running for some time, ghost impulses because the 
+RasPi GPIOs seems somewhat unreliable (at least when reading them using Python), even when always using optocouplers on the impulse inputs. 
+
+## Functions
+- Data logging, implemented in 2 manners:
+  - InfluxDB (current reading, current momentary power/usage)
+  - file log (only daily minimum and total value)
+- calculation of momentary power (or usage, depending on meter type) from measured time between impulses received from capturing module
+- MQTT publishing of all current values
+- calculation of todays/yesterdays total usage and publishing it over MQTT (only if file logging is enabled)
+- configurable multiple InfluxDB instances (i.E. different DBs for a power meter and a gas meter and also for momentary (power) and long term (energy readings) data of the same meter)
+- additional interval for energy readings, not to flood InfluxDB with data every few seconds as the hardware outputs data on every detected impulse (not implemented for momentary readings as there a high resolution is desired in the logs)
+
+
+
+## Installation
+
+This example describes my setup - running on a Raspberry Pi 3/4 as user "pi".
+
+1. extract s0meters folder to /home/pi/s0meters
+
+2. install prerequisites:
+
+   - Python 3
+
+   - Python 3 modules:
+
+     - pyserial
+     - paho-mqtt
+     - PyYAML
+     - influxdb
+
+     ```sh
+     pip3 install pyserial paho-mqtt PyYAML influxdb
+     ```
+
+3. copy or symlink s0meters.service to /etc/systemd/system, 
+
+   then reload systemctl and start service: 
+
+   ```sh
+   sudo ln -s s0meters.service /etc/systemd/system
+   or
+   sudo cp s0meters.service /etc/systemd/system
+   
+   sudo systemctl daemon-reload
+   sudo systemctl enable s0meters.service
+   ```
+
+4. edit configuration to your needs (see below)
+
+5. when configuration is finished (and tested in interactive mode), start service: 
+
+   ```sh
+   sudo systemctl start s0meters.service
+   ```
+
+6. check if it is still running after some time:
+
+   ```sh
+   sudo systemctl status s0meters.service
+   ```
+
+
+
+## Configuration
+
+Configuration is split in 3 parts. 
+Base configuration is in ini format - most parameters are self describing
+
+#### Main configuration
+
+config file: s0meters.ini
+
+```ini
+[main]
+# add timestamps to console output in debug/verbose mode
+consoleAddTimestamp = true
+
+# additional YAML config files
+meters_config_yml = s0meters.yml
+influx_config_yml = s0meters_influxdb.yml
+
+[hardware]
+serialPort = /dev/ttyUSB0
+serialBaud = 57600
+serialTout = 1
+
+[filelog]
+# needed for calculating today/yesterday totals, so only disable if that is not needed
+enable = True
+
+# storage path must be existing and writable for the user that runs s0meters.py (sub directories are created as needed)
+storage_path = /home/pi/s0meters
+
+[mqtt]
+enable = true
+server = mqtt.lan
+port = 1883
+keepalive = 60
+user = mqttuser
+password = *******
+
+# MQTT topics
+# Note: this is only for status infos and commands, meters Out-Topics must be defined in the meters configuration!
+# In-Topic for sending commands to the device
+topic_cmd = Top5/ImpCount/cmd
+# Out-Topic
+topic_stat = Top5/ImpCount/stat
+# Out-Topic for response to commands (can be the same as topic_stat)
+topic_cmdresponse = Top5/ImpCount/cmdResponse
+
+```
+
+
+
+#### Meters configuration
+
+config file: meters.yml (unless differently defined in s0meters.ini)
+
+In this YAML styled config file, all meters/counters are declared. The main identifier is the counter number used in the hardware counter module, so for "C1" the identifier is 1 and so on. 
+
+```yaml
+1: # meter ID as used in counter hardware (="C1")
+  name: "Power"
+  impPerUnit: 1000
+  unit: "kWh"
+  digits: 3
+  momType: "power"
+  #momUnit: "kW"
+  #momDigits: 3
+  #momFactor: 1
+  momUnit: "W"
+  momDigits: 0
+  momFactor: 1000
+  statTopic: "Powermeter"
+  influxInstance_energy: "energymeters"
+  influxInstance_mom: "energy_momentary"
+  influxMeasurement_energy: "energy"
+  influxMeasurement_mom: "energy"
+  influxFieldName_energy: "Energy_Total__kWh"
+  influxFieldName_mom: "Power__W"
+  influxMinWriteInterval_energy: 300
+2: # meter ID as used in counter hardware (="C2")
+  name: "Gas"
+  impPerUnit: 100
+  unit: "m3"
+  digits: 2
+  type: "usage"
+  momType: "momUsage"
+  momUnit: "m3/h"
+  momDigits: 2
+  momFactor: 1
+  statTopic: "Gasmeter"
+  influxInstance_energy: "energymeters"
+  influxInstance_mom: "energy_momentary"
+  influxMeasurement_energy: "gas"
+  influxMeasurement_mom: "gas"
+  influxFieldName_energy: "Gas_Total__m3"
+  influxFieldName_mom: "Gas_Usage__m3_h"
+  influxMinWriteInterval_energy: 300
+```
+
+- **name**: free text, used for path of file log and internally
+
+- **impPerUnit**: integer, normally 10, 100 or 1000, used for calculation of momentary units
+
+- **unit**: free text, currently only used in MQTT JSON output
+
+- **digits**: integer, number of digits in output of counter reading
+
+- **momType**: type of momentary reading. used as MQTT sub-topic
+
+- **momUnit**: free text, currently only used in MQTT JSON output
+
+- **momDigits**: integer, number of digits in output of momentary value
+
+- **momFactor**: factor for calculation of momentary value
+
+  Formula for calculation: momValue = (3600000 / dTime / impPerUnit) * momFactor
+  where dTime = time between impulses in milliseconds
+
+  Normally 1, except if the unit of momentary value should be different - for example:  
+
+  - power meter, 1000 imp per unit = 1 kWh: 
+    momFactor=1000 -> output in Watts
+    momFactor=1 -> output in kW
+  - gas meter, 100 imp per unit = 1m³:
+    momFactor=1 --> output in m³/h
+    momFactor=1000 --> output in dm³/h (l/h)
+
+- **statTopic**: MQTT topic prefix to publish all values of this meter
+  i.E. if statTopic = "Powermeter", following topics will be published to: 
+  - Powermeter/reading = current counter reading (total)
+  - Powermeter/today = increase of counter reading today
+  - Powermeter/yesterday = increase of counter reading yesterday
+  - Powermeter/[momType] = current value of momentary value ("power" for example 1, "usage" for example 2)
+  - Powermeter/json = JSON formatted output containing all values
+- **influxInstance**_energy: a valid InfluxDB instance from s0meters_influxdb.yml where energy/counter readings are written to
+- **influxInstance**_mom: a valid InfluxDB instance from s0meters_influxdb.yml where momentary values are written to
+- **influxMeasurement_energy**: InfluxDB measurement name for energy (total counter value)
+- **influxMeasurement_mom**: InfluxDB measurement name for momentary values
+- **influxFieldName_energy**: InfluxDB field name for energy (total counter value)
+- **influxFieldName_mom**: InfluxDB measurement name for momentary value
+- **influxMinWriteInterval**_energy: minimal InfluxDB write interval for energy readings
+  If no interval is configured, EVERY impulse received will be written to InfluxDB!
+  There is no such option for the momentary value, as there a high resolution is desired in the logs. 
+
+
+
+#### InfluxDB configuration
+
+config file: s0meters_influx.yml (unless differently defined in s0meters.ini)
+
+- It is possible to define as many InfluxDB instances as needed
+- Every instance has its identifier which must be unique
+- It is only necessary to define different instances if the database name or server is different. If only the measurement name differs, that can be set in the meters configuration for each meter
+- defaultMeasurement is not really necessary as normally the used measurement name should be defined for each meter in the meters configuration YAML
+- All other parameters here are self describing. Comment out/remove username/password if the server does not use it. 
+
+```yaml
+energymeters:
+  host: localhost
+  port: 8086
+  username: s0meters
+  password: ********
+  database: energymeters
+  defaultMeasurement: energy
+energy_momentary:
+  host: localhost
+  port: 8086
+  username: s0meters
+  password: ********
+  database: energy_momentary
+  defaultMeasurement: energy
+
+```
+
+
+
+
+
+# controlarduino.py, flasharduino.sh
+
+Tools for serial monitor and to reset and flash Arduino board that supports it with ***reset [ms]***command. 
+
+**controlarduino.py** is used by ***flasharduino.sh*** to reset the MCU. 
+
+This alternate reset/flash method can be used for Arduino based projects with: 
+
+- no direct USB connection
+- UART connection available, but without DTS line (used by Arduino for resetting into bootloader), regardless of the reason
+- when UART DTS is intentionally disconnected to prevent from sudden reset, which could lead to data loss (such as in this project with the counters eventually not yet stored to EEPROM)
+
+In this project a *reset [ms]* command is built into the Arduino software which resets the hardware by pulling /RESET to low using a dedicated (normally *INPUT*) GPIO pin. This resets the Arduino in such a way, that it will start up in bootloader mode and can be flashed using avrdude. This reset command also calls a save-all-data-to-EEPROM routine before doing the actual reset. 
+
+**flasharduino.sh** sends the reset command using controlarduino.py, flashes the MCU using avrdude and then starts controlarduino.py in --monitor mode. 

+ 61 - 0
S0Meters_py/controlarduino.py

@@ -0,0 +1,61 @@
+#!/usr/bin/python3 -u
+#
+import serial
+import sys
+import argparse
+from datetime import datetime
+
+serialPort='/dev/serial/by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller-if00-port0'
+serialBaud=57600
+serialTimeout=1
+
+doReset = False
+enableMonitor = False
+
+ser = serial.Serial(port=serialPort,
+    baudrate = serialBaud,
+    parity=serial.PARITY_NONE,
+    stopbits=serial.STOPBITS_ONE,
+    bytesize=serial.EIGHTBITS,
+    timeout=serialTimeout)
+
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--reset',
+                    help='reset board via serial command, parameter is timeout in ms to reset.')
+parser.add_argument('--monitor', default=False,
+                    help='Monitor serial output.', action='store_true')
+parser.add_argument('--addts', default=False,
+                    help='Add timestamp to monitor output.', action='store_true')
+
+args = parser.parse_args()
+    
+if args.reset:
+    if int(args.reset) >= 1:
+        doReset = True
+        delayTime = args.reset
+
+if doReset:
+    cmdStr = 'reset ' + str(delayTime) + '\n'
+    #print('cmd: >' + cmdStr + '<')
+    cmdStr = cmdStr.encode('utf-8')
+    ser.write(cmdStr)
+
+if args.monitor:
+    while True:
+        #ser.flushInput()        
+        #read buffer until cr/lf
+        serLine = ser.readline().strip()
+        # catch exception on invalid char coming in: UnicodeDecodeError: 'ascii' codec can't decode byte 0xf4 in position 6: ordinal not in range(128)
+        try: 
+            serLine = serLine.decode('ascii')
+        except:
+            serLine = ""
+    
+        if(serLine):
+            if args.addts:
+                #print (datetime.now().isoformat(), serLine)    #Echo the serial buffer bytes up to the CRLF back to screen
+                print ("[" + str(datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]) + "]:", serLine)
+            else:
+                print (serLine)    #Echo the serial buffer bytes up to the CRLF back to screen
+            

+ 7 - 0
S0Meters_py/flasharduino.sh

@@ -0,0 +1,7 @@
+#!/bin/sh
+PORT=/dev/serial/by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller-if00-port0
+BAUD=57600
+
+python3 ./controlarduino.py --reset 1000
+avrdude -patmega328p -carduino -P$PORT -b$BAUD -D -Uflash:w:$1:i
+python3 ./controlarduino.py --monitor --addts

+ 38 - 0
S0Meters_py/s0meters.ini

@@ -0,0 +1,38 @@
+[main]
+# add timestamps to console output in debug/verbose mode
+consoleAddTimestamp = true
+
+# additional YAML config files
+meters_config_yml = s0meters.yml
+influx_config_yml = s0meters_influxdb.yml
+
+[hardware]
+serialPort = /dev/serial/by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller-if00-port0
+serialBaud = 57600
+serialTout = 1
+
+[filelog]
+# needed for calculating today/yesterday totals, so only disable if that is not needed
+enable = True
+
+# storage path must be existing and writable for the user that runs s0meters.py (sub directories are created as needed)
+storage_path = /home/pi/s0meters
+
+[mqtt]
+enable = true
+server = mqtt.lan
+port = 1883
+keepalive = 60
+user = script
+password = rlAzqusqfbAy
+#user = "jeelink2mqtt"
+#password = "jFiUyMBuhOFX"
+
+# MQTT topics
+# Note: this is only for status infos and commands, meters Out-Topics must be defined in the meters configuration!
+# In-Topic for sending commands to the device
+topic_cmd = Top5/ImpCount/cmd
+# Out-Topic
+topic_stat = Top5/ImpCount/stat
+# Out-Topic for response to commands (can be the same as topic_stat)
+topic_cmdresponse = Top5/ImpCount/cmdResponse

+ 487 - 0
S0Meters_py/s0meters.py

@@ -0,0 +1,487 @@
+#!/usr/bin/python3 -u
+#
+import serial
+#from time import sleep
+import time
+import os
+import sys
+import paho.mqtt.client as mqtt
+import json
+import yaml
+from yaml.constructor import ConstructorError
+from threading import Thread
+from influxdb import InfluxDBClient
+import configparser
+#from datetime import datetime
+import datetime
+
+# Change working dir to the same dir as this script
+os.chdir(sys.path[0])
+
+config = configparser.ConfigParser()
+config.read('s0meters.ini')
+
+quiet = False
+verbose = False
+debug = False
+
+if len(sys.argv) >= 2:
+    if sys.argv[1] == "-q":
+        verbose = False
+        quiet = True
+        debug = False
+    elif sys.argv[1] == "-v":
+        verbose = True
+        quiet = False
+        debug = False
+        print("VERBOSE=ON")
+    elif sys.argv[1] == "-d":
+        verbose = True
+        quiet = False
+        debug = True
+        print("DEBUG=ON")
+
+
+consoleAddTimestamp = config['main'].get('consoleAddTimestamp')
+
+
+conf_storage_path = config['filelog'].get('storage_path')
+if conf_storage_path[-1:] != '/':
+    conf_storage_path += '/'
+
+
+ser = serial.Serial(port=config['hardware'].get('serialPort'),
+    baudrate = config['hardware'].get('serialBaud'),
+    parity=serial.PARITY_NONE,
+    stopbits=serial.STOPBITS_ONE,
+    bytesize=serial.EIGHTBITS,
+    timeout=config['hardware'].getint('serialTout'))
+
+
+
+if not quiet:
+    print("S0MetersLog by Flo Kra")
+    print("=======================================================================")
+
+meters_yaml = yaml.load(open(config['main'].get('meters_config_yml')), Loader=yaml.SafeLoader)
+if not quiet:
+    print("Meters configuration:")
+    print(json.dumps(meters_yaml, indent=2))
+    
+    print("loading InfluxDB configuration...")
+    
+influxdb_yaml = yaml.load(open(config['main'].get('influx_config_yml')), Loader=yaml.SafeLoader)
+
+if not quiet:
+    print("InfluxDB Instances:")
+    print(json.dumps(influxdb_yaml, indent=4))
+
+influxclient = dict()
+for instance in influxdb_yaml:
+    i_host = influxdb_yaml[instance].get('host', None)
+    i_port = int(influxdb_yaml[instance].get('port', 8086))
+    i_username = influxdb_yaml[instance].get('username', None)
+    i_password = influxdb_yaml[instance].get('password', None)
+    i_database = influxdb_yaml[instance].get('database', None)
+    if i_host != None and i_database != None:
+        if i_username != None and i_password != None:
+            influxclient[instance] = InfluxDBClient(i_host, i_port, i_username, i_password, i_database)
+        else:
+            influxclient[instance] = InfluxDBClient(i_host, i_port, i_database)
+
+
+data_energy = dict()
+data_momentary = dict()
+saved_todays_date = dict()
+influxdb_energy_lastWriteTime = dict()
+
+saved_energy_today_min = dict()
+saved_energy_yesterday_total = dict()
+
+for meter in meters_yaml:
+    data_energy[meter] = dict()
+    data_momentary[meter] = dict()
+
+
+MQTTenabled = config['mqtt'].getboolean('enable', False)
+
+if MQTTenabled:
+    def on_connect(client, userdata, flags, rc):
+        if not quiet:
+            print("MQTT: connected with result code " + str(rc))
+        client.subscribe(config['mqtt'].get('topic_cmd'))
+        if not quiet:
+            print("MQTT: subscribed topic:", config['mqtt'].get('topic_cmd'))
+        
+    def on_message(client, userdata, msg):    
+        if not quiet:
+            print("MQTT incoming on topic", msg.topic)
+        if msg.topic == config['mqtt'].get('topic_cmd'):
+            if not quiet:
+                print("MQTT CMD:", msg.payload)
+            cmd = msg.payload.decode('ascii') + '\n'
+            ser.write(cmd.encode('ascii'))
+
+    mqttc = mqtt.Client()
+    mqttc.on_connect = on_connect
+    #mqttc.on_disconnect = on_disconnect
+    mqttc.on_message = on_message
+    
+    if config['mqtt'].get('user') != "" and config['mqtt'].get('password') != "":
+        mqttc.username_pw_set(config['mqtt'].get('user'), config['mqtt'].get('password'))
+    mqttc.connect(config['mqtt'].get('server'), config['mqtt'].getint('port'), config['mqtt'].getint('keepalive'))
+    
+    mqttc.loop_start()
+
+
+def processMeterData(data):
+    try:
+        cJson = json.loads(data)
+    except:
+        cJson = False
+    #print(json.dumps(cJson, indent=1))
+    #print(cJson['C'])
+    #print(json.dumps(meters_yaml[cJson['C']]))
+    #print(json.dumps(cJson))
+    
+    if cJson:
+        cNum = cJson.get('C')
+        cReading = float(cJson.get('reading', None))
+        #print(cNum)
+        
+        dTime = cJson.get('dTime', None)
+        
+        write_energy_to_influxdb = False
+        
+        cName = meters_yaml[cNum].get('name', False)
+        statTopic = meters_yaml[cNum].get('statTopic', False)
+        unit = meters_yaml[cNum].get('unit', False)
+        
+        momUnit = meters_yaml[cNum].get('momUnit', False)
+        momType = meters_yaml[cNum].get('momType', False)
+        
+        impPerUnit = meters_yaml[cNum].get('impPerUnit', False)
+        
+        if cName:
+            cJson['name'] = cName
+        
+        momFactor = meters_yaml[cNum].get('momFactor', False)
+        if not momFactor:
+            momFactor = 1
+        
+        momDigits = meters_yaml[cNum].get('momDigits', None)
+        if momDigits == None:
+            momDigits = 3
+        
+        digits = meters_yaml[cNum].get('digits', False)
+        
+        influxMinWriteInterval = meters_yaml[cNum].get('influxMinWriteInterval_energy', None)
+        if influxMinWriteInterval == None: influxMinWriteInterval = 0
+        
+        
+        # check for date rollover since last impulse
+        today = datetime.date.today()
+        today_str = today.strftime('%Y%m%d')
+        yesterday = today - datetime.timedelta(days = 1)
+        yesterday_str = yesterday.strftime('%Y%m%d')
+        dateRollover = False
+        savedtoday = saved_todays_date.get(cName, False)
+        if not savedtoday or savedtoday != today:
+            if debug:
+                print("date rollover happened or no date has been saved yet for meter " + str(cName))
+            if savedtoday and savedtoday == yesterday:
+                # a date rollover just happened, so change todays date to current and proceed with what has to be done
+                dateRollover = True
+                #log.debug(savedtoday)
+            saved_todays_date[cName] = today
+        
+        
+        strformat = "{:.3f}"
+        cReading_formatted = None
+        if digits:
+            strformat = "{:."+str(digits)+"f}"
+            cReading_formatted = strformat.format(cReading)
+            cJson['reading'] = round(cReading, digits)
+        
+        if unit:
+            cJson['unit'] = unit
+        
+        if impPerUnit and dTime is not None:
+            if dTime == 0:
+                momValue = 0.0
+            else:
+                momValue = (3600000 / dTime / impPerUnit) * momFactor
+            
+            if momDigits > 0:
+                momValue = round(momValue, momDigits)
+            else:
+                momValue = round(momValue)
+                
+            cJson['momValue'] = momValue
+            if momType:
+                cJson['momType'] = momType
+            if momUnit:
+                cJson['momUnit'] = momUnit
+            
+            if statTopic:
+                if momType and momValue is not None:
+                    if MQTTenabled: 
+                        subtop = momType
+                        mqttc.publish(statTopic + "/" + subtop, str(momValue), qos=0, retain=False)
+            
+        if statTopic:
+            if cReading_formatted != None:
+                if MQTTenabled: 
+                    mqttc.publish(statTopic + "/reading", str(cReading_formatted), qos=0, retain=False)
+        
+        
+        data_energy[cNum][meters_yaml[cNum].get('influxFieldName_energy', 'energyTotal')] = round(float(cReading), digits)
+        data_momentary[cNum][meters_yaml[cNum].get('influxFieldName_mom', 'momentaryUsage')] = round(float(momValue), momDigits)
+        
+        # InfluxDB
+        t_utc = datetime.datetime.utcnow()
+        t_str = t_utc.isoformat() + 'Z'
+        
+        
+        
+        # InfluxDB - energy readings
+        if dateRollover:
+            write_energy_to_influxdb = True
+            
+        ts = int(time.time())
+        influxEnergyWrite_elapsedTime = 0
+        if influxdb_energy_lastWriteTime.get(cNum, None) != None:
+            influxEnergyWrite_elapsedTime = ts - influxdb_energy_lastWriteTime.get(cNum)
+            if influxEnergyWrite_elapsedTime >= influxMinWriteInterval:
+                write_energy_to_influxdb = True
+                influxdb_energy_lastWriteTime[cNum] = ts
+        else:
+            # first run - do write immediately
+            write_energy_to_influxdb = True
+            influxdb_energy_lastWriteTime[cNum] = ts
+            
+        
+        influxInstance_energy = meters_yaml[cNum].get('influxInstance_energy', None)
+        if influxInstance_energy is not None:
+            if write_energy_to_influxdb:
+                influx_measurement = meters_yaml[cNum].get('influxMeasurement_energy', None)
+                if influx_measurement == None:
+                    influx_measurement = influxdb_yaml[influxInstance_energy].get('defaultMeasurement', 'energy')
+                    
+                jsondata_energy = [
+                    {
+                        'measurement': influx_measurement,
+                        'tags': {
+                            'meter': cName,
+                        },
+                        'time': t_str,
+                        'fields': data_energy[cNum]
+                    }
+                ]
+                if verbose:
+                    print("Writing ENERGY to InfluxDB:")
+                    print(json.dumps(jsondata_energy, indent = 4))
+                try:
+                    #influxclient_energy.write_points(jsondata_energy)
+                    influxclient[influxInstance_energy].write_points(jsondata_energy)
+                except Exception as e:
+                    print('Data not written!')
+                    #log.error('Data not written!')
+                    print(e)
+                    #log.error(e)
+            else:
+                if verbose:
+                    print("Writing ENERGY to InfluxDB skipped (influxMinWriteInterval="+ str(influxMinWriteInterval) + ", elapsedTime=" + str(influxEnergyWrite_elapsedTime) + ")")
+        
+        
+        # InfluxDB - momentary values
+        influxInstance_mom = meters_yaml[cNum].get('influxInstance_mom', None)
+        if influxInstance_mom is not None:
+            influx_measurement = meters_yaml[cNum].get('influxMeasurement_mom', None)
+            if influx_measurement == None:
+                influx_measurement = influxdb_yaml[influxInstance_mom].get('defaultMeasurement', 'energy')
+                
+            jsondata_momentary = [
+                {
+                    'measurement': influx_measurement,
+                    'tags': {
+                        'meter': cName,
+                    },
+                    'time': t_str,
+                    'fields': data_momentary[cNum]
+                }
+            ]
+            if verbose:
+                print("Writing MOMENTARY to InfluxDB:")
+                print(json.dumps(jsondata_momentary, indent = 4))
+            try:
+                #influxclient_momentary.write_points(jsondata_momentary)
+                influxclient[influxInstance_mom].write_points(jsondata_momentary)
+            except Exception as e:
+                print('Data not written!')
+                #log.error('Data not written!')
+                print(e)
+                #log.error(e)
+                
+        
+        # file log
+        if config['filelog'].getboolean('enable'):
+            # save and restore yesterday´s total energy to calculate today´s energy
+            # check if total energy from yesterday is stored in memory, if not try to get it from saved file
+            
+            file_path_meter = conf_storage_path + cName + "/"
+            file_today_min = file_path_meter + today_str + "_min.txt"
+            file_yesterday_total = file_path_meter + yesterday_str + "_total.txt"
+            
+            energy_today_total = 0
+            energy_yesterday_min = 0
+            energy_today_min = saved_energy_today_min.get(cName, None)
+            
+            try:
+                if dateRollover:
+                    energy_today_min = None
+                    
+                if energy_today_min == None:
+                    exists = os.path.isfile(file_today_min)
+                    if exists:
+                        # load energy_today_min from file if exists
+                        f = open(file_today_min, "r")
+                        if f.mode == 'r':
+                            contents = f.read()
+                            f.close()
+                        if contents != '':
+                            energy_today_min = float(contents)
+                            saved_energy_today_min[cName] = energy_today_min
+                            if verbose:
+                                print(cName + " - Energy Today min read from file -> = " + str(energy_today_min))
+                        else: energy_today_min = None
+                    else:
+                        # save current Energy_total to min-file
+                        if not os.path.exists(file_path_meter):
+                            os.mkdir(file_path_meter)
+                        f = open(file_today_min, "w+")
+                        energy_today_min = cReading
+                        saved_energy_today_min[cName] = energy_today_min
+                        #f.write(str('{0:.3f}'.format(energy_today_min)))
+                        #f.write(str(energy_today_min))
+                        f.write(strformat.format(energy_today_min))
+                        f.close()
+                        
+                #try:
+                if energy_today_min != None:
+                    energy_today_total = cReading - energy_today_min
+                    if verbose:
+                        print(cName + " - Energy Today total: " + str('{0:.3f}'.format(energy_today_total)))
+                
+                
+                energy_yesterday_total = saved_energy_yesterday_total.get(cName, None)
+                if dateRollover:
+                    energy_yesterday_total = None
+                if energy_yesterday_total == None:
+                    exists = os.path.isfile(file_yesterday_total)
+                    if exists:
+                        # load energy_yesterday_total from file if exists
+                        f = open(file_yesterday_total, "r")
+                        if f.mode == 'r':
+                            contents = f.read()
+                            f.close()
+                        if contents != '':
+                            energy_yesterday_total = float(contents)
+                            saved_energy_yesterday_total[cName] = energy_yesterday_total
+                            if debug:
+                                print(cName + " - Energy Yesterday total read from file -> = " + str(energy_yesterday_total))
+                        else: energy_yesterday_total = None
+                    else:
+                        file_yesterday_min = file_path_meter + yesterday_str + "_min.txt"
+                        exists = os.path.isfile(file_yesterday_min)
+                        if exists:
+                            # load yesterday_min from file
+                            #if args_output_verbose1:
+                            #    print("file file_yesterday_min exists")
+                            f = open(file_yesterday_min, "r")
+                            if f.mode == 'r':
+                                contents =f.read()
+                                f.close()
+                            
+                            if contents != '':
+                                energy_yesterday_min = float(contents)
+                                if debug:
+                                    print(cName + " - Energy yesterday min: " + str(energy_yesterday_min))
+                            else: energy_yesterday_min = None
+                            
+                            if energy_yesterday_min != None:
+                                energy_yesterday_total = round(energy_today_min - energy_yesterday_min, 3)
+                                ###log.debug(meter_id_name[meter['id']] + " - Energy yesterday total: " + str(energy_yesterday_total))
+                            
+                                if not os.path.exists(file_path_meter):
+                                    os.mkdir(file_path_meter)
+                                f = open(file_yesterday_total, "w+")
+                                #f.write(str('{0:.3f}'.format(energy_yesterday_total)))
+                                f.write(strformat.format(energy_yesterday_total))
+                                f.close()
+                            #else:
+                            #    # file yesterday_min does not exist
+            except:
+                e = sys.exc_info()[0]
+                print( "<p>Error in file log: %s</p>" % e )
+            
+            if energy_today_total is not None:
+                cJson['Today'] = round(energy_today_total, digits)
+                if MQTTenabled: 
+                    mqttc.publish(statTopic + "/today", str(round(energy_today_total, digits)), qos=0, retain=False)
+                
+            if energy_yesterday_total is not None:
+                cJson['Yesterday'] = round(energy_yesterday_total, digits)
+                if MQTTenabled: 
+                    mqttc.publish(statTopic + "/yesterday", str(round(energy_yesterday_total, digits)), qos=0, retain=False)
+        # END file log 
+        
+        if verbose:
+            if consoleAddTimestamp:
+                print ("[" + str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]) + "] meterData:", json.dumps(cJson))
+            else:
+                print("meterData:", json.dumps(cJson))
+        
+        if MQTTenabled: 
+            mqttc.publish(statTopic + "/json", json.dumps(cJson), qos=0, retain=False)
+
+def publishStatMsg(data):
+    if MQTTenabled: 
+        mqttc.publish(config['mqtt'].get('topic_stat'), data, qos=0, retain=False)
+
+def publishCmdResponseMsg(data):
+    if MQTTenabled: 
+        mqttc.publish(config['mqtt'].get('topic_cmdresponse'), data, qos=0, retain=False)
+
+
+try:
+    while True:
+        serLine = ser.readline().strip()
+        # catch exception on invalid char coming in: UnicodeDecodeError: 'ascii' codec can't decode byte 0xf4 in position 6: ordinal not in range(128)
+        try: 
+            serLine = serLine.decode('ascii')
+        except:
+            serLine = ""
+
+        if(serLine):
+            if verbose:
+                if consoleAddTimestamp:
+                    print ("[" + str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]) + "] DEV_SENT: ", serLine)
+                else:
+                    print ("DEV_SENT: ", serLine)    #Echo the serial buffer bytes up to the CRLF back to screen
+            
+            # check if data looks like meter readings JSON - then process
+            if serLine.startswith('{"C":'):
+                Thread(target=processMeterData, args=(serLine,)).start()
+            
+            # response to a command
+            elif serLine.startswith('cmd:'):
+                Thread(target=publishCmdResponseMsg, args=(serLine,)).start()
+            
+            # other cases it is a normal "stat" message
+            else:
+                Thread(target=publishStatMsg, args=(serLine,)).start()
+            
+except KeyboardInterrupt:
+    print('\n')
+    exit()

+ 13 - 0
S0Meters_py/s0meters.service

@@ -0,0 +1,13 @@
+[Unit]
+Description=S0MetersLogger
+StartLimitInterval=0
+
+[Service]
+Type=simple
+Restart=always
+RestartSec=1
+ExecStart=/home/pi/s0meters/s0meters.py -q
+User=pi
+
+[Install]
+WantedBy=multi-user.target

+ 38 - 0
S0Meters_py/s0meters.yml

@@ -0,0 +1,38 @@
+1:
+  name: "Power"
+  impPerUnit: 1000
+  unit: "kWh"
+  digits: 3
+  momType: "power"
+  #momUnit: "kW"
+  #momDigits: 3
+  #momFactor: 1
+  momUnit: "W"
+  momDigits: 0
+  momFactor: 1000
+  statTopic: "Powermeter"
+  influxInstance_energy: "energymeters"
+  influxInstance_mom: "energy_momentary"
+  influxMeasurement_energy: "energy"
+  influxMeasurement_mom: "energy"
+  influxFieldName_energy: "Energy_Total__kWh"
+  influxFieldName_mom: "Power__W"
+  influxMinWriteInterval_energy: 300
+2:
+  name: "Gas"
+  impPerUnit: 100
+  unit: "m3"
+  digits: 2
+  type: "usage"
+  momType: "momUsage"
+  momUnit: "m3/h"
+  momDigits: 2
+  momFactor: 1
+  statTopic: "Gasmeter"
+  influxInstance_energy: "energymeters"
+  influxInstance_mom: "energy_momentary"
+  influxMeasurement_energy: "gas"
+  influxMeasurement_mom: "gas"
+  influxFieldName_energy: "Gas_Total__m3"
+  influxFieldName_mom: "Gas_Usage__m3_h"
+  influxMinWriteInterval_energy: 300

+ 14 - 0
S0Meters_py/s0meters_influxdb.yml

@@ -0,0 +1,14 @@
+energymeters:
+  host: localhost
+  port: 8086
+  username: s0meters
+  password: 
+  database: energymeters
+  defaultMeasurement: energy
+energy_momentary:
+  host: localhost
+  port: 8086
+  username: s0meters
+  password: 
+  database: energy_momentary
+  defaultMeasurement: energy