├── .github └── workflows │ └── build.yml ├── .travis.yml.bak ├── 3DDruck ├── LTB_Weather_Station │ ├── LICENSE.txt │ ├── LTB_Weather_Station.ino │ ├── README.txt │ ├── attribution_card.html │ ├── files │ │ ├── 01Anem_Cup.stl │ │ ├── 02Anem_center.stl │ │ ├── 03Anem_Base.stl │ │ ├── 04Anem_bracket.stl │ │ ├── 11Direc_pointer.stl │ │ ├── 12Direc_base.stl │ │ ├── 13Direc_bracket.stl │ │ ├── 31Rain_FlipFlop.stl │ │ ├── 32Rain_Base.stl │ │ ├── 33Rain_Funnel.stl │ │ ├── 34Rain_PartFunnel.stl │ │ ├── 41Fram_T_piece.stl │ │ ├── 42Fram_Base.stl │ │ ├── Anemometer.scad │ │ └── RainGuage.scad │ └── images │ │ ├── 0f729904a5f2e05334bc5dd88b66ae25_preview_featured.jpg │ │ ├── 117a4e0169dc935ad4cb069c9b1e4cbd_preview_featured.jpg │ │ ├── 15661ac53241d97e30403f3ccd07a3a0_preview_featured.jpg │ │ ├── 19405cb05ae3fd27b113e646ea3810c1_preview_featured.jpg │ │ ├── 2c7b42b0f8cd26165a07a06924028e5b_preview_featured.jpg │ │ ├── 2f4eb67d5eb4e4a115d83a93fdd548bd_preview_featured.jpg │ │ ├── 3d7bd073ae92bd9a4f123ed83592e2da_preview_featured.jpg │ │ ├── 4128c8499053c0b8ed6bece59226a6e4_preview_featured.jpg │ │ ├── 45c1245175a171400667a6d880b7b2a3_preview_featured.jpg │ │ ├── 5851a940cc2cf8ce6b7ae1dae2f9f374_preview_featured.jpg │ │ ├── 665cde6034edafd1919697d14e3cbb7f_preview_featured.jpg │ │ ├── 6b7efd5bf7d866a3c7be1622005885e2_preview_featured.jpg │ │ ├── 6f4c261a202a8efb6d09fc4429fcd451_preview_featured.jpg │ │ ├── 6f54eee4d5941a1848efe295c70625fb_preview_featured.jpg │ │ ├── 7844c83e0afc9eee98446c4f50ffa83b_preview_featured.jpg │ │ ├── 7dec8525ebd62560725952abd26e961d_preview_featured.jpg │ │ ├── 80a48253a995d0b735cc264a9117a01e_preview_featured.jpg │ │ ├── 8c24a9ce323ae254777e71005f5087d5_preview_featured.jpg │ │ ├── 9245b32cea09aa1bce04a988e750eaf5_preview_featured.jpg │ │ ├── a46b4e9dc1ee91424486a30a58d59f65_preview_featured.jpg │ │ ├── aa5c15dc5b5677d0f9d4d23d35d61b8d_preview_featured.jpg │ │ ├── abda42896f2a54828468f4c982fa79e0_preview_featured.jpg │ │ ├── b8ac2ffeab8d6cb9135d3699e298f246_preview_featured.jpg │ │ ├── c9b82732129711d131ec30678b11e9f1_preview_featured.jpg │ │ ├── e383737310d1c1f831bcede16474fa9f_preview_featured.jpg │ │ ├── ef46951516978715a64110eb92978627_preview_featured.jpg │ │ ├── f5733b1c9a6c24a76b0aa705a5f0eb99_preview_featured.jpg │ │ └── ff516d27357b673a9011a6b4d327566e_preview_featured.jpg └── Luftdaten_Stevensson_screen │ ├── LICENSE.txt │ ├── README.txt │ ├── attribution_card.html │ ├── files │ ├── middle_part_x6.STL │ ├── sds011_holder_x1.STL │ ├── top_part_x1.STL │ └── wall_bottom_part_x1.STL │ └── images │ ├── 160ce06f31e4f0b9b2863523b1d578d7_preview_featured.jpg │ ├── 44aee935f5d444104dc200fb56da6abe_preview_featured.jpg │ ├── 4de7b6a64d3845ae190a4616e7cf8708_preview_featured.jpg │ ├── da4376fd09404e2d7904c5d9ae312a6a_preview_featured.jpg │ ├── de5c749b48ccad6f2da1c18631324c17_preview_featured.jpg │ └── e4547351a65a82ecb83e4decc64e33e9_preview_featured.jpg ├── AS3935_Calibration └── AS3935_Calibration.ino ├── HB-UNI-Sen-WEA.ino ├── I2C.cpp ├── I2C.h ├── Images ├── 0.JPG ├── 1.JPG ├── 2.JPG ├── 3.JPG ├── 4.png ├── Arduino_Boardverwaltung.png ├── BME_PFTE.jpeg ├── CCU_Addon.png ├── CCU_Bedienung.png ├── CCU_DV_Regen.png ├── CCU_DV_Sturm.png ├── CCU_Einstellungen.png ├── CCU_Experteneinstellungen.png ├── CCU_Geraet.png ├── Connect_AS3935.jpeg ├── PCB_Connectors.jpeg ├── Platine_bestueckt.jpg ├── as3935_back_rot.png ├── sample1_1.jpg ├── sample1_2.jpg ├── sample1_3.jpg ├── wiring.fzz └── wiring.png ├── Luftdruck_Tendenz.txt ├── PWFusion_AS3935.cpp ├── PWFusion_AS3935.h ├── PWFusion_AS3935_I2C.cpp ├── PWFusion_AS3935_I2C.h ├── README.md ├── RaindetectorStallBizTest └── RaindetectorStallBizTest.ino ├── Renkforce_WindVane ├── 2016-11-12-21.50.05.jpg └── Renkforce_WindVane.ino ├── Sensors ├── PCF8574_WindDir.h ├── Sens_As3935.h ├── Sens_As5600.h ├── Sens_Bme280.h └── VentusW132.h ├── WinddirResistorTest └── WinddirResistorTest.ino ├── ci ├── arduino-cli.yaml ├── download-sketch.sh ├── install-deps.sh └── sen-wea.sh └── docs ├── AS3935.pdf ├── AS5600.pdf ├── MAX44009.pdf └── VEML6070.pdf /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | pull_request: 4 | schedule: 5 | - cron: '0 2 * * *' # run at 2 AM UTC 6 | workflow_dispatch: 7 | jobs: 8 | build-sketches: 9 | runs-on: ubuntu-20.04 10 | 11 | steps: 12 | # GIT Checkout 13 | - uses: actions/checkout@v2 14 | 15 | - name: Setup Arduino CLI 16 | uses: arduino/setup-arduino-cli@v1.1.1 17 | with: 18 | version: "0.17.0" 19 | 20 | - name: Install Libs and Cores 21 | run: ci/install-deps.sh 22 | 23 | - name: Download sketch 24 | run: ci/download-sketch.sh 25 | 26 | - name: Compile Sketches 27 | run: ci/sen-wea.sh 28 | -------------------------------------------------------------------------------- /.travis.yml.bak: -------------------------------------------------------------------------------- 1 | language: c 2 | before_install: 3 | - wget https://downloads.arduino.cc/arduino-1.8.1-linux64.tar.xz 4 | - tar xf arduino-1.8.1-linux64.tar.xz 5 | - sudo mv arduino-1.8.1 /usr/local/share/arduino 6 | - sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino 7 | install: 8 | - arduino --pref "boardsmanager.additional.urls=https://downloads.arduino.cc/packages/package_avr_3.6.0_index.json" --save-prefs 9 | - git clone --branch=master https://github.com/GreyGnome/EnableInterrupt.git /usr/local/share/arduino/libraries/EnableInterrupt 10 | - git clone --branch=master https://github.com/pa-pa/AskSinPP.git /usr/local/share/arduino/libraries/AskSinPP 11 | - git clone --branch=master https://github.com/rocketscream/Low-Power.git /usr/local/share/arduino/libraries/Low-Power 12 | - git clone --branch=master https://github.com/finitespace/BME280.git /usr/local/share/arduino/libraries/BME280 13 | - arduino --install-boards arduino:avr:1.8.2 14 | script: 15 | - arduino --verify --pref update.check=false --board arduino:avr:pro:cpu=8MHzatmega328 $PWD/HB-UNI-Sen-WEA.ino 16 | notifications: 17 | email: 18 | on_failure: always 19 | -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/LICENSE.txt: -------------------------------------------------------------------------------- 1 | LTB Weather Station (https://www.thingiverse.com/thing:2849562) by RobWLakes is licensed under the Creative Commons - Attribution - Non-Commercial license. 2 | http://creativecommons.org/licenses/by-nc/3.0/ 3 | 4 | -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/LTB_Weather_Station.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #define WINDCOUNTER_PIN 5 3 | 4 | //Wind Speed 5 | float radius = 0.065; //metres from center pin to middle of cup 6 | int seconds = 0; 7 | int revolutions = 0; //counted by interrupt 8 | int rps = -1; // read revs per second (5 second interval) 9 | int mps = 0; //wind speed metre/sec 10 | 11 | 12 | 13 | void setup() { 14 | Serial.begin(57600); 15 | pinMode(WINDCOUNTER_PIN, INPUT_PULLUP); 16 | if ( digitalPinToInterrupt(WINDCOUNTER_PIN) == NOT_AN_INTERRUPT ) enableInterrupt(WINDCOUNTER_PIN, rps_fan, FALLING); else attachInterrupt(digitalPinToInterrupt(WINDCOUNTER_PIN), rps_fan, FALLING); 17 | // Initialize Timer1 for a 1 second interrupt 18 | // Thanks to http://www.engblaze.com/ for this section, see their Interrupt Tutorial 19 | cli(); // disable global interrupts 20 | TCCR1A = 0; // set entire TCCR1A register to 0 21 | TCCR1B = 0; // same for TCCR1B 22 | // set compare match register to desired timer count: 23 | OCR1A = 15624; 24 | // turn on CTC mode: 25 | TCCR1B |= (1 << WGM12); 26 | // Set CS10 and CS12 bits for 1024 prescaler: 27 | TCCR1B |= (1 << CS10); 28 | TCCR1B |= (1 << CS12); 29 | // enable timer compare interrupt: 30 | TIMSK1 |= (1 << OCIE1A); 31 | // enable global interrupts: 32 | sei(); 33 | } // setup() 34 | 35 | //Routine Driven by Interrupt, trap 1 second interrupts, and output every 5 seconds 36 | ISR(TIMER1_COMPA_vect) { 37 | seconds++; 38 | if (seconds == 5) { //make 5 for each output 39 | seconds = 0; 40 | rps = revolutions; 41 | revolutions = 0; 42 | } 43 | } 44 | 45 | // executed every time the interrupt 0 (pin2) gets low, ie one rev of cups. 46 | void rps_fan() { 47 | revolutions++; 48 | }//end of interrupt routine 49 | 50 | 51 | void loop() { 52 | 53 | while (true) { 54 | 55 | if (rps != -1) { //Update every 5 seconds, this will be equal to reading frequency (Hz)x5. 56 | float kmph = rps * 3.1414 * 2 * radius * 12 * 60 / 1000; 57 | 58 | Serial.println("km/h = " + String(kmph)); 59 | Serial.println("revs = "+String(revolutions)); 60 | } 61 | 62 | delay(1000); 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/README.txt: -------------------------------------------------------------------------------- 1 | .: :, 2 | ,:::::::: ::` ::: ::: 3 | ,:::::::: ::` ::: ::: 4 | .,,:::,,, ::`.:, ... .. .:, .:. ..`... ..` .. .:, .. :: .::, .:,` 5 | ,:: ::::::: ::, ::::::: `:::::::.,:: ::: ::: .:::::: ::::: :::::: .:::::: 6 | ,:: :::::::: ::, :::::::: ::::::::.,:: ::: ::: :::,:::, ::::: ::::::, :::::::: 7 | ,:: ::: ::: ::, ::: :::`::. :::.,:: ::,`::`::: ::: ::: `::,` ::: ::: 8 | ,:: ::. ::: ::, ::` :::.:: ::.,:: :::::: ::::::::: ::` :::::: ::::::::: 9 | ,:: ::. ::: ::, ::` :::.:: ::.,:: .::::: ::::::::: ::` ::::::::::::::: 10 | ,:: ::. ::: ::, ::` ::: ::: `:::.,:: :::: :::` ,,, ::` .:: :::.::. ,,, 11 | ,:: ::. ::: ::, ::` ::: ::::::::.,:: :::: :::::::` ::` ::::::: :::::::. 12 | ,:: ::. ::: ::, ::` ::: :::::::`,:: ::. :::::` ::` :::::: :::::. 13 | ::, ,:: `` 14 | :::::::: 15 | :::::: 16 | `,,` 17 | 18 | 19 | https://www.thingiverse.com/thing:2849562 20 | LTB Weather Station by RobWLakes is licensed under the Creative Commons - Attribution - Non-Commercial license. 21 | http://creativecommons.org/licenses/by-nc/3.0/ 22 | 23 | # Summary 24 | 25 | Weather Stations are a very useful devices, and as we increase our knowledge of the global weather, quantifying our own local experience is also popular. Integrating aspects of the weather to IoT is increasingly important. 26 | 27 | This project does not invent anything much new, but should give a working set of plans for a weather enthusiast to build their own station. The design is somewhat double-brick out-house in most places and has not been designed for hi-res printing with wafer thin walls. However it will produce a robust system that people may like to refine themselves. The OpenSCAD files are provided to allow people to customise the designs. The system was designed and built for an Arts/Science Exhibition, FLOAT, as a demonstration station, but has been wired up and demonstrates the usual functions. A cutaway funnel is also provided, which was used with the Rain Gauge for this exhibition. 28 | 29 | The system also has the Arduino program included to illustrate how the the weather station can be interfaced, processed and results displayed. The Arduino program, as it stands, does not provide any definite calibration for rain and wind speed (if it is accurate, that has happened only by chance :-). Wind direction, Temperature and Barometric pressure are accurate. If you build it, and use my Arduino program, you will have to spend some time calibrating wind speed, and fine tuning rainfall. 30 | 31 | The non-printable extras I used are listed below, and in the OpenSCAD and Arduino scripts. Plus the Arduino gear.... (I added a Barometric/Temperature sensor, but an obvious extension would be to add Humidity as well.) 32 | 33 | Some suggestions for mounting the sensors are provided, along with glue on brackets and fittings to construct a simple "T" frame combined with aluminium tubing, however this can be adapted as circumstances dictate. 34 | 35 | # Post-Printing 36 | 37 | ## Extra hints 38 | 39 | The thrust bearings should be a tight fit and not require glue. The 5mm brass tube for the axles though will benefit from some cyanoacrylate on the ABS to hold them in place. Rough the tube up a bit with sandpaper or a file to help adhesion. The Temperature and Barometric pressure does not need calibrating. However Rainfall (it is fairly close) and wind speed will need calibration. As long as the magnet in the wind direction sensor is close enough to trigger two adjacent reed switches when half way between the two reeds, it will allow 8 reed switches to reliably indicate 16 directions. 40 | 41 | The reed switches in the direction indicator are vertical and are not trimmed, just the top end curled over to allow easy soldering to the common earth wire ring. Extra spacing maybe required, eg a small ring of heat shrink tubing to keep the moving parts of the anemometer and wind speed separated and seated on the bearings in the stationary base. This was too fine to print. 42 | 43 | All the magnets N-S poles should be aligned along the line of the reed switch. The magnet lines of force between N-S have the best switching effect, not one of the poles, N or S, on its own. This also helps eliminate bounce, or multiple triggering. 44 | 45 | ## Non-printable Parts List 46 | 47 | Arduino Uno Board + Prototyping Shield 48 | 10 of Magnetic Reed Switches, glass 14mm x 2mm 49 | 4 Thrust Bearings 8mm OD x2.5mm by 5 mm ID 50 | 3 Neodymium magnets 3mmOD x 2mm 51 | Scrap brass tube OD 5mm (eg Car Radio Antenna) 52 | Hook up wire 53 | BMP085 Barometer/Temperature breakout (I2C) 54 | PCF8574 I2C to LCD interface board 55 | 4x20 characters HD44780-compatible LCD 56 | 2mm steel axle for Tipping Bucket flip flop 57 | Plastic tubing for spaces eg Heat shrink 58 | 59 | ## Extensions 60 | 61 | The Arduino system as described has a major shortcoming, it is assumed the sensors will be close to the CPU and there will be no long runs of cable. If longer cables are contemplated then larger pull-up resistors than the internally programmed pull-ups maybe required on all the reed switches. Very long cables may not be possible or recommended. 62 | 63 | Mounting the computer close to the sensors and building a radio link maybe the best alternative, and using some other board than a UNO with at least 10 pins I/O free and some Wi-Fi could give a good combination. eg 64 | https://hackaday.com/2017/11/13/weather-station-needs-almost-no-batteries/ 65 | 66 | Battery power poses even more challenges, but a larger battery charged by a solar panel is a viable option these days. Designing ultra low power electronic gear is a specialist area. 67 | 68 | ## Printing times with 0.4mm nozzle, 30% fill and Support 69 | 70 | 3 Anemometer Cups and arms 1h21m (x3) = 4h3m 71 | Anemometer Arm Hub 3h31m 72 | Anemometer base 2h 73 | Anemometer Bracket 16m 74 | Wind Direction Vane 4h21m 75 | Wind Direction Base 3h30m 76 | Wind Direction Bracket 16m 77 | Tipping Buckets 1h43m 78 | Rain Gauge base 6h18m 79 | Rain Gauge Funnel (full) 12h30m (Invert to print to avoid Support printing) 80 | 81 | Estimated total 35 hours of Printing -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/attribution_card.html: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 |
16 |
17 | 18 |
19 |

LTB Weather Station by RobWLakes

20 |

Published on April 4, 2018

21 |

www.thingiverse.com/thing:2849562

22 |

23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
34 | Creative Commons - Attribution - Non-Commercial

35 |
36 | 37 | 42 | -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/files/13Direc_bracket.stl: -------------------------------------------------------------------------------- 1 | solid OpenSCAD_Model 2 | facet normal -0.994522 0.10453 0 3 | outer loop 4 | vertex -9.78148 2.07912 -5 5 | vertex -9.81934 1.71882 -4.67793 6 | vertex -9.78148 2.07912 -4.51752 7 | endloop 8 | endfacet 9 | facet normal -0.994522 0.104529 -7.34407e-07 10 | outer loop 11 | vertex -9.78148 2.07912 -5 12 | vertex -9.8376 1.54508 -4.75528 13 | vertex -9.81934 1.71882 -4.67793 14 | endloop 15 | endfacet 16 | facet normal -0.994522 0.104529 -1.50578e-06 17 | outer loop 18 | vertex -9.78148 2.07912 -5 19 | vertex -9.94507 0.522642 -4.97261 20 | vertex -9.8376 1.54508 -4.75528 21 | endloop 22 | endfacet 23 | facet normal -0.994522 0.104529 1.6472e-05 24 | outer loop 25 | vertex -10 0 -5 26 | vertex -9.94507 0.522642 -4.97261 27 | vertex -9.78148 2.07912 -5 28 | endloop 29 | endfacet 30 | facet normal -0.994522 0.10453 0 31 | outer loop 32 | vertex -9.94507 0.522642 -4.97261 33 | vertex -10 0 -5 34 | vertex -10 0 -4.97261 35 | endloop 36 | endfacet 37 | facet normal -0.994522 0.10453 0 38 | outer loop 39 | vertex -9.81934 1.71882 4.67793 40 | vertex -9.78148 2.07912 5 41 | vertex -9.78148 2.07912 4.51752 42 | endloop 43 | endfacet 44 | facet normal -0.994522 0.104529 6.5502e-07 45 | outer loop 46 | vertex -9.8376 1.54508 4.75528 47 | vertex -9.78148 2.07912 5 48 | vertex -9.81934 1.71882 4.67793 49 | endloop 50 | endfacet 51 | facet normal -0.994522 0.104529 1.50578e-06 52 | outer loop 53 | vertex -9.94507 0.522642 4.97261 54 | vertex -9.78148 2.07912 5 55 | vertex -9.8376 1.54508 4.75528 56 | endloop 57 | endfacet 58 | facet normal -0.994522 0.10453 0 59 | outer loop 60 | vertex -10 0 5 61 | vertex -9.94507 0.522642 4.97261 62 | vertex -10 0 4.97261 63 | endloop 64 | endfacet 65 | facet normal -0.994522 0.104529 -1.6472e-05 66 | outer loop 67 | vertex -9.94507 0.522642 4.97261 68 | vertex -10 0 5 69 | vertex -9.78148 2.07912 5 70 | endloop 71 | endfacet 72 | facet normal 0 1 -0 73 | outer loop 74 | vertex 1.04528 9.94522 -5 75 | vertex -1.04528 9.94522 5 76 | vertex 1.04528 9.94522 5 77 | endloop 78 | endfacet 79 | facet normal 0 1 0 80 | outer loop 81 | vertex -1.04528 9.94522 5 82 | vertex 1.04528 9.94522 -5 83 | vertex -1.04528 9.94522 -5 84 | endloop 85 | endfacet 86 | facet normal -0.743145 0.669131 0 87 | outer loop 88 | vertex -8.09017 5.87785 -5 89 | vertex -6.69131 7.43145 5 90 | vertex -6.69131 7.43145 -5 91 | endloop 92 | endfacet 93 | facet normal -0.743145 0.669131 0 94 | outer loop 95 | vertex -6.69131 7.43145 5 96 | vertex -8.09017 5.87785 -5 97 | vertex -8.09017 5.87785 5 98 | endloop 99 | endfacet 100 | facet normal -0.866026 0.5 0 101 | outer loop 102 | vertex -8.09017 5.87785 -5 103 | vertex -8.597 5 0 104 | vertex -8.09017 5.87785 5 105 | endloop 106 | endfacet 107 | facet normal -0.866025 0.500001 2.2105e-07 108 | outer loop 109 | vertex -8.09017 5.87785 -5 110 | vertex -8.65594 4.8979 -0.971369 111 | vertex -8.597 5 0 112 | endloop 113 | endfacet 114 | facet normal -0.866022 0.500005 1.8158e-06 115 | outer loop 116 | vertex -8.09017 5.87785 -5 117 | vertex -8.66008 4.89074 -1.03956 118 | vertex -8.65594 4.8979 -0.971369 119 | endloop 120 | endfacet 121 | facet normal -0.866025 0.5 -3.42886e-08 122 | outer loop 123 | vertex -8.09017 5.87785 -5 124 | vertex -8.84657 4.56773 -2.03368 125 | vertex -8.66008 4.89074 -1.03956 126 | endloop 127 | endfacet 128 | facet normal -0.866026 0.5 0 129 | outer loop 130 | vertex -9.13545 4.06737 -2.90033 131 | vertex -8.09017 5.87785 -5 132 | vertex -9.13545 4.06737 -5 133 | endloop 134 | endfacet 135 | facet normal -0.866026 0.5 -2.3494e-07 136 | outer loop 137 | vertex -8.09017 5.87785 -5 138 | vertex -9.13545 4.06737 -2.90033 139 | vertex -8.84657 4.56773 -2.03368 140 | endloop 141 | endfacet 142 | facet normal -0.866025 0.500001 -2.2105e-07 143 | outer loop 144 | vertex -8.65594 4.8979 0.971369 145 | vertex -8.09017 5.87785 5 146 | vertex -8.597 5 0 147 | endloop 148 | endfacet 149 | facet normal -0.866022 0.500005 -1.8158e-06 150 | outer loop 151 | vertex -8.66008 4.89074 1.03956 152 | vertex -8.09017 5.87785 5 153 | vertex -8.65594 4.8979 0.971369 154 | endloop 155 | endfacet 156 | facet normal -0.866025 0.5 3.42886e-08 157 | outer loop 158 | vertex -8.84657 4.56773 2.03368 159 | vertex -8.09017 5.87785 5 160 | vertex -8.66008 4.89074 1.03956 161 | endloop 162 | endfacet 163 | facet normal -0.866026 0.5 2.3494e-07 164 | outer loop 165 | vertex -9.13545 4.06737 2.90033 166 | vertex -8.09017 5.87785 5 167 | vertex -8.84657 4.56773 2.03368 168 | endloop 169 | endfacet 170 | facet normal -0.866026 0.5 0 171 | outer loop 172 | vertex -8.09017 5.87785 5 173 | vertex -9.13545 4.06737 2.90033 174 | vertex -9.13545 4.06737 5 175 | endloop 176 | endfacet 177 | facet normal -0.406737 0.913545 0 178 | outer loop 179 | vertex -3.09017 9.51056 -5 180 | vertex -5 8.66025 5 181 | vertex -3.09017 9.51056 5 182 | endloop 183 | endfacet 184 | facet normal -0.406737 0.913545 0 185 | outer loop 186 | vertex -5 8.66025 5 187 | vertex -3.09017 9.51056 -5 188 | vertex -5 8.66025 -5 189 | endloop 190 | endfacet 191 | facet normal 0.207912 0.978148 -0 192 | outer loop 193 | vertex 2.02143 9.73773 -5 194 | vertex 1.04528 9.94522 5 195 | vertex 2.02143 9.73773 5 196 | endloop 197 | endfacet 198 | facet normal 0.207912 0.978148 0 199 | outer loop 200 | vertex 1.04528 9.94522 5 201 | vertex 2.02143 9.73773 -5 202 | vertex 1.04528 9.94522 -5 203 | endloop 204 | endfacet 205 | facet normal -0.951058 0.309013 0 206 | outer loop 207 | vertex -9.13545 4.06737 -5 208 | vertex -9.14269 4.04508 -2.93893 209 | vertex -9.13545 4.06737 -2.90033 210 | endloop 211 | endfacet 212 | facet normal -0.951056 0.309017 4.70819e-08 213 | outer loop 214 | vertex -9.13545 4.06737 -5 215 | vertex -9.36995 3.34565 -3.71572 216 | vertex -9.14269 4.04508 -2.93893 217 | endloop 218 | endfacet 219 | facet normal -0.951058 0.309013 -2.53065e-06 220 | outer loop 221 | vertex -9.13545 4.06737 -5 222 | vertex -9.40866 3.22653 -3.80227 223 | vertex -9.36995 3.34565 -3.71572 224 | endloop 225 | endfacet 226 | facet normal -0.951057 0.309017 4.1292e-07 227 | outer loop 228 | vertex -9.13545 4.06737 -5 229 | vertex -9.64472 2.5 -4.33013 230 | vertex -9.40866 3.22653 -3.80227 231 | endloop 232 | endfacet 233 | facet normal -0.951057 0.309017 2.08391e-07 234 | outer loop 235 | vertex -9.78148 2.07912 -5 236 | vertex -9.64472 2.5 -4.33013 237 | vertex -9.13545 4.06737 -5 238 | endloop 239 | endfacet 240 | facet normal -0.951056 0.309017 0 241 | outer loop 242 | vertex -9.64472 2.5 -4.33013 243 | vertex -9.78148 2.07912 -5 244 | vertex -9.78148 2.07912 -4.51752 245 | endloop 246 | endfacet 247 | facet normal -0.951058 0.309013 0 248 | outer loop 249 | vertex -9.14269 4.04508 2.93893 250 | vertex -9.13545 4.06737 5 251 | vertex -9.13545 4.06737 2.90033 252 | endloop 253 | endfacet 254 | facet normal -0.951056 0.309017 -4.70819e-08 255 | outer loop 256 | vertex -9.36995 3.34565 3.71572 257 | vertex -9.13545 4.06737 5 258 | vertex -9.14269 4.04508 2.93893 259 | endloop 260 | endfacet 261 | facet normal -0.951058 0.309014 2.28386e-06 262 | outer loop 263 | vertex -9.40866 3.22653 3.80227 264 | vertex -9.13545 4.06737 5 265 | vertex -9.36995 3.34565 3.71572 266 | endloop 267 | endfacet 268 | facet normal -0.951057 0.309017 -3.2504e-07 269 | outer loop 270 | vertex -9.64472 2.5 4.33013 271 | vertex -9.13545 4.06737 5 272 | vertex -9.40866 3.22653 3.80227 273 | endloop 274 | endfacet 275 | facet normal -0.951056 0.309017 0 276 | outer loop 277 | vertex -9.78148 2.07912 5 278 | vertex -9.64472 2.5 4.33013 279 | vertex -9.78148 2.07912 4.51752 280 | endloop 281 | endfacet 282 | facet normal -0.951057 0.309017 -2.08391e-07 283 | outer loop 284 | vertex -9.64472 2.5 4.33013 285 | vertex -9.78148 2.07912 5 286 | vertex -9.13545 4.06737 5 287 | endloop 288 | endfacet 289 | facet normal 0 0 1 290 | outer loop 291 | vertex 1.04528 9.94522 5 292 | vertex 0.546309 5.19779 5 293 | vertex 2.02143 9.73773 5 294 | endloop 295 | endfacet 296 | facet normal -0 0 1 297 | outer loop 298 | vertex -3.09017 9.51056 5 299 | vertex 0.546309 5.19779 5 300 | vertex -1.04528 9.94522 5 301 | endloop 302 | endfacet 303 | facet normal -0 0 1 304 | outer loop 305 | vertex -1.04528 9.94522 5 306 | vertex 0.546309 5.19779 5 307 | vertex 1.04528 9.94522 5 308 | endloop 309 | endfacet 310 | facet normal 0 0 1 311 | outer loop 312 | vertex 0.546309 -5.19779 5 313 | vertex 1.04528 -9.94522 5 314 | vertex 2.02143 -9.73773 5 315 | endloop 316 | endfacet 317 | facet normal -0 0 1 318 | outer loop 319 | vertex -5 8.66025 5 320 | vertex 0.546309 5.19779 5 321 | vertex -3.09017 9.51056 5 322 | endloop 323 | endfacet 324 | facet normal 0 0 1 325 | outer loop 326 | vertex 0.546309 -5.19779 5 327 | vertex -1.04528 -9.94522 5 328 | vertex 1.04528 -9.94522 5 329 | endloop 330 | endfacet 331 | facet normal -0 0 1 332 | outer loop 333 | vertex -6.69131 7.43145 5 334 | vertex 0.546309 5.19779 5 335 | vertex -5 8.66025 5 336 | endloop 337 | endfacet 338 | facet normal -0 0 1 339 | outer loop 340 | vertex -8.09017 5.87785 5 341 | vertex 0.546309 5.19779 5 342 | vertex -6.69131 7.43145 5 343 | endloop 344 | endfacet 345 | facet normal 0 0 1 346 | outer loop 347 | vertex 0.546309 -5.19779 5 348 | vertex -3.09017 -9.51056 5 349 | vertex -1.04528 -9.94522 5 350 | endloop 351 | endfacet 352 | facet normal 0 0 1 353 | outer loop 354 | vertex 0.546309 5.19779 5 355 | vertex -8.09017 5.87785 5 356 | vertex 0 0 5 357 | endloop 358 | endfacet 359 | facet normal 0 0 1 360 | outer loop 361 | vertex 0.546309 -5.19779 5 362 | vertex -5 -8.66025 5 363 | vertex -3.09017 -9.51056 5 364 | endloop 365 | endfacet 366 | facet normal -0 0 1 367 | outer loop 368 | vertex -9.13545 4.06737 5 369 | vertex 0 0 5 370 | vertex -8.09017 5.87785 5 371 | endloop 372 | endfacet 373 | facet normal 0 0 1 374 | outer loop 375 | vertex 0.546309 -5.19779 5 376 | vertex -6.69131 -7.43145 5 377 | vertex -5 -8.66025 5 378 | endloop 379 | endfacet 380 | facet normal -0 0 1 381 | outer loop 382 | vertex -9.78148 2.07912 5 383 | vertex 0 0 5 384 | vertex -9.13545 4.06737 5 385 | endloop 386 | endfacet 387 | facet normal 0 0 1 388 | outer loop 389 | vertex 0.546309 -5.19779 5 390 | vertex -8.09017 -5.87785 5 391 | vertex -6.69131 -7.43145 5 392 | endloop 393 | endfacet 394 | facet normal 0 0 1 395 | outer loop 396 | vertex -10 0 5 397 | vertex 0 0 5 398 | vertex -9.78148 2.07912 5 399 | endloop 400 | endfacet 401 | facet normal 0 0 1 402 | outer loop 403 | vertex 0 0 5 404 | vertex -8.09017 -5.87785 5 405 | vertex 0.546309 -5.19779 5 406 | endloop 407 | endfacet 408 | facet normal 0 -0 1 409 | outer loop 410 | vertex -9.78148 -2.07912 5 411 | vertex 0 0 5 412 | vertex -10 0 5 413 | endloop 414 | endfacet 415 | facet normal 0 -0 1 416 | outer loop 417 | vertex -8.09017 -5.87785 5 418 | vertex 0 0 5 419 | vertex -9.13545 -4.06737 5 420 | endloop 421 | endfacet 422 | facet normal 0 -0 1 423 | outer loop 424 | vertex -9.13545 -4.06737 5 425 | vertex 0 0 5 426 | vertex -9.78148 -2.07912 5 427 | endloop 428 | endfacet 429 | facet normal -0.587785 0.809017 0 430 | outer loop 431 | vertex -5 8.66025 -5 432 | vertex -6.69131 7.43145 5 433 | vertex -5 8.66025 5 434 | endloop 435 | endfacet 436 | facet normal -0.587785 0.809017 0 437 | outer loop 438 | vertex -6.69131 7.43145 5 439 | vertex -5 8.66025 -5 440 | vertex -6.69131 7.43145 -5 441 | endloop 442 | endfacet 443 | facet normal -0.207911 0.978148 0 444 | outer loop 445 | vertex -1.04528 9.94522 -5 446 | vertex -3.09017 9.51056 5 447 | vertex -1.04528 9.94522 5 448 | endloop 449 | endfacet 450 | facet normal -0.207911 0.978148 0 451 | outer loop 452 | vertex -3.09017 9.51056 5 453 | vertex -1.04528 9.94522 -5 454 | vertex -3.09017 9.51056 -5 455 | endloop 456 | endfacet 457 | facet normal -0.207911 -0.978148 0 458 | outer loop 459 | vertex -3.09017 -9.51056 -5 460 | vertex -1.04528 -9.94522 5 461 | vertex -3.09017 -9.51056 5 462 | endloop 463 | endfacet 464 | facet normal -0.207911 -0.978148 -0 465 | outer loop 466 | vertex -1.04528 -9.94522 5 467 | vertex -3.09017 -9.51056 -5 468 | vertex -1.04528 -9.94522 -5 469 | endloop 470 | endfacet 471 | facet normal 0.207912 -0.978148 0 472 | outer loop 473 | vertex 1.04528 -9.94522 -5 474 | vertex 2.02143 -9.73773 5 475 | vertex 1.04528 -9.94522 5 476 | endloop 477 | endfacet 478 | facet normal 0.207912 -0.978148 0 479 | outer loop 480 | vertex 2.02143 -9.73773 5 481 | vertex 1.04528 -9.94522 -5 482 | vertex 2.02143 -9.73773 -5 483 | endloop 484 | endfacet 485 | facet normal -0.866026 -0.5 0 486 | outer loop 487 | vertex -8.09017 -5.87785 -5 488 | vertex -9.13545 -4.06737 -2.90033 489 | vertex -9.13545 -4.06737 -5 490 | endloop 491 | endfacet 492 | facet normal -0.866026 -0.5 -2.3494e-07 493 | outer loop 494 | vertex -9.13545 -4.06737 -2.90033 495 | vertex -8.09017 -5.87785 -5 496 | vertex -8.84657 -4.56773 -2.03368 497 | endloop 498 | endfacet 499 | facet normal -0.866023 -0.500003 8.13693e-07 500 | outer loop 501 | vertex -8.60079 -4.99344 -0.0624554 502 | vertex -8.09017 -5.87785 -5 503 | vertex -8.597 -5 0 504 | endloop 505 | endfacet 506 | facet normal -0.866026 -0.5 -6.69294e-08 507 | outer loop 508 | vertex -8.66008 -4.89074 -1.03956 509 | vertex -8.09017 -5.87785 -5 510 | vertex -8.60079 -4.99344 -0.0624554 511 | endloop 512 | endfacet 513 | facet normal -0.866025 -0.5 -3.42886e-08 514 | outer loop 515 | vertex -8.84657 -4.56773 -2.03368 516 | vertex -8.09017 -5.87785 -5 517 | vertex -8.66008 -4.89074 -1.03956 518 | endloop 519 | endfacet 520 | facet normal -0.866026 -0.5 2.3494e-07 521 | outer loop 522 | vertex -8.09017 -5.87785 5 523 | vertex -9.13545 -4.06737 2.90033 524 | vertex -8.84657 -4.56773 2.03368 525 | endloop 526 | endfacet 527 | facet normal -0.866025 -0.5 3.42886e-08 528 | outer loop 529 | vertex -8.09017 -5.87785 5 530 | vertex -8.84657 -4.56773 2.03368 531 | vertex -8.66008 -4.89074 1.03956 532 | endloop 533 | endfacet 534 | facet normal -0.866025 -0.5 -0 535 | outer loop 536 | vertex -8.09017 -5.87785 5 537 | vertex -8.597 -5 0 538 | vertex -8.09017 -5.87785 -5 539 | endloop 540 | endfacet 541 | facet normal -0.866023 -0.500003 -8.13693e-07 542 | outer loop 543 | vertex -8.597 -5 0 544 | vertex -8.09017 -5.87785 5 545 | vertex -8.60079 -4.99344 0.0624554 546 | endloop 547 | endfacet 548 | facet normal -0.866026 -0.5 0 549 | outer loop 550 | vertex -9.13545 -4.06737 2.90033 551 | vertex -8.09017 -5.87785 5 552 | vertex -9.13545 -4.06737 5 553 | endloop 554 | endfacet 555 | facet normal -0.866026 -0.5 6.69294e-08 556 | outer loop 557 | vertex -8.60079 -4.99344 0.0624554 558 | vertex -8.09017 -5.87785 5 559 | vertex -8.66008 -4.89074 1.03956 560 | endloop 561 | endfacet 562 | facet normal -0.994522 -0.10453 0 563 | outer loop 564 | vertex -10 0 -5 565 | vertex -9.94507 -0.522642 -4.97261 566 | vertex -10 0 -4.97261 567 | endloop 568 | endfacet 569 | facet normal -0.994522 -0.104529 1.6472e-05 570 | outer loop 571 | vertex -9.78148 -2.07912 -5 572 | vertex -9.94507 -0.522642 -4.97261 573 | vertex -10 0 -5 574 | endloop 575 | endfacet 576 | facet normal -0.994522 -0.104529 -1.50578e-06 577 | outer loop 578 | vertex -9.78148 -2.07912 -5 579 | vertex -9.8376 -1.54508 -4.75528 580 | vertex -9.94507 -0.522642 -4.97261 581 | endloop 582 | endfacet 583 | facet normal -0.994522 -0.104529 0 584 | outer loop 585 | vertex -9.8376 -1.54508 -4.75528 586 | vertex -9.78148 -2.07912 -5 587 | vertex -9.78148 -2.07912 -4.51752 588 | endloop 589 | endfacet 590 | facet normal -0.994522 -0.10453 0 591 | outer loop 592 | vertex -9.94507 -0.522642 4.97261 593 | vertex -10 0 5 594 | vertex -10 0 4.97261 595 | endloop 596 | endfacet 597 | facet normal -0.994522 -0.104529 -1.6472e-05 598 | outer loop 599 | vertex -9.94507 -0.522642 4.97261 600 | vertex -9.78148 -2.07912 5 601 | vertex -10 0 5 602 | endloop 603 | endfacet 604 | facet normal -0.994522 -0.104529 1.50578e-06 605 | outer loop 606 | vertex -9.8376 -1.54508 4.75528 607 | vertex -9.78148 -2.07912 5 608 | vertex -9.94507 -0.522642 4.97261 609 | endloop 610 | endfacet 611 | facet normal -0.994522 -0.104529 -0 612 | outer loop 613 | vertex -9.78148 -2.07912 5 614 | vertex -9.8376 -1.54508 4.75528 615 | vertex -9.78148 -2.07912 4.51752 616 | endloop 617 | endfacet 618 | facet normal -0.951057 -0.309017 0 619 | outer loop 620 | vertex -9.78148 -2.07912 -5 621 | vertex -9.64472 -2.5 -4.33013 622 | vertex -9.78148 -2.07912 -4.51752 623 | endloop 624 | endfacet 625 | facet normal -0.951057 -0.309017 -1.21561e-07 626 | outer loop 627 | vertex -9.13545 -4.06737 -5 628 | vertex -9.64472 -2.5 -4.33013 629 | vertex -9.78148 -2.07912 -5 630 | endloop 631 | endfacet 632 | facet normal -0.951057 -0.309017 -2.55712e-07 633 | outer loop 634 | vertex -9.64472 -2.5 -4.33013 635 | vertex -9.13545 -4.06737 -5 636 | vertex -9.36995 -3.34565 -3.71572 637 | endloop 638 | endfacet 639 | facet normal -0.951056 -0.309017 4.70819e-08 640 | outer loop 641 | vertex -9.13545 -4.06737 -5 642 | vertex -9.14269 -4.04508 -2.93893 643 | vertex -9.36995 -3.34565 -3.71572 644 | endloop 645 | endfacet 646 | facet normal -0.951058 -0.309013 0 647 | outer loop 648 | vertex -9.14269 -4.04508 -2.93893 649 | vertex -9.13545 -4.06737 -5 650 | vertex -9.13545 -4.06737 -2.90033 651 | endloop 652 | endfacet 653 | facet normal -0.951056 -0.309017 0 654 | outer loop 655 | vertex -9.69739 -2.33791 4.40229 656 | vertex -9.78148 -2.07912 5 657 | vertex -9.78148 -2.07912 4.51752 658 | endloop 659 | endfacet 660 | facet normal -0.951057 -0.309016 -3.791e-07 661 | outer loop 662 | vertex -9.64472 -2.5 4.33013 663 | vertex -9.78148 -2.07912 5 664 | vertex -9.69739 -2.33791 4.40229 665 | endloop 666 | endfacet 667 | facet normal -0.951057 -0.309017 -1.54086e-07 668 | outer loop 669 | vertex -9.13545 -4.06737 5 670 | vertex -9.64472 -2.5 4.33013 671 | vertex -9.60074 -2.63537 4.23178 672 | endloop 673 | endfacet 674 | facet normal -0.951057 -0.309017 3.2949e-07 675 | outer loop 676 | vertex -9.13545 -4.06737 5 677 | vertex -9.60074 -2.63537 4.23178 678 | vertex -9.36995 -3.34565 3.71572 679 | endloop 680 | endfacet 681 | facet normal -0.951057 -0.309017 1.15767e-08 682 | outer loop 683 | vertex -9.64472 -2.5 4.33013 684 | vertex -9.13545 -4.06737 5 685 | vertex -9.78148 -2.07912 5 686 | endloop 687 | endfacet 688 | facet normal -0.951056 -0.309017 -4.70819e-08 689 | outer loop 690 | vertex -9.14269 -4.04508 2.93893 691 | vertex -9.13545 -4.06737 5 692 | vertex -9.36995 -3.34565 3.71572 693 | endloop 694 | endfacet 695 | facet normal -0.951058 -0.309013 -0 696 | outer loop 697 | vertex -9.13545 -4.06737 5 698 | vertex -9.14269 -4.04508 2.93893 699 | vertex -9.13545 -4.06737 2.90033 700 | endloop 701 | endfacet 702 | facet normal 0 -1 0 703 | outer loop 704 | vertex -1.04528 -9.94522 -5 705 | vertex 1.04528 -9.94522 5 706 | vertex -1.04528 -9.94522 5 707 | endloop 708 | endfacet 709 | facet normal 0 -1 -0 710 | outer loop 711 | vertex 1.04528 -9.94522 5 712 | vertex -1.04528 -9.94522 -5 713 | vertex 1.04528 -9.94522 -5 714 | endloop 715 | endfacet 716 | facet normal -0.406737 -0.913545 0 717 | outer loop 718 | vertex -5 -8.66025 -5 719 | vertex -3.09017 -9.51056 5 720 | vertex -5 -8.66025 5 721 | endloop 722 | endfacet 723 | facet normal -0.406737 -0.913545 -0 724 | outer loop 725 | vertex -3.09017 -9.51056 5 726 | vertex -5 -8.66025 -5 727 | vertex -3.09017 -9.51056 -5 728 | endloop 729 | endfacet 730 | facet normal -0.743145 -0.669131 0 731 | outer loop 732 | vertex -6.69131 -7.43145 -5 733 | vertex -8.09017 -5.87785 5 734 | vertex -8.09017 -5.87785 -5 735 | endloop 736 | endfacet 737 | facet normal -0.743145 -0.669131 0 738 | outer loop 739 | vertex -8.09017 -5.87785 5 740 | vertex -6.69131 -7.43145 -5 741 | vertex -6.69131 -7.43145 5 742 | endloop 743 | endfacet 744 | facet normal 0 0 -1 745 | outer loop 746 | vertex 1.04528 -9.94522 -5 747 | vertex 0.546309 -5.19779 -5 748 | vertex 2.02143 -9.73773 -5 749 | endloop 750 | endfacet 751 | facet normal 0 0 -1 752 | outer loop 753 | vertex -3.09017 -9.51056 -5 754 | vertex 0.546309 -5.19779 -5 755 | vertex -1.04528 -9.94522 -5 756 | endloop 757 | endfacet 758 | facet normal 0 0 -1 759 | outer loop 760 | vertex -1.04528 -9.94522 -5 761 | vertex 0.546309 -5.19779 -5 762 | vertex 1.04528 -9.94522 -5 763 | endloop 764 | endfacet 765 | facet normal 0 0 -1 766 | outer loop 767 | vertex 0.546309 5.19779 -5 768 | vertex 1.04528 9.94522 -5 769 | vertex 2.02143 9.73773 -5 770 | endloop 771 | endfacet 772 | facet normal 0 0 -1 773 | outer loop 774 | vertex -5 -8.66025 -5 775 | vertex 0.546309 -5.19779 -5 776 | vertex -3.09017 -9.51056 -5 777 | endloop 778 | endfacet 779 | facet normal 0 0 -1 780 | outer loop 781 | vertex 0.546309 5.19779 -5 782 | vertex -1.04528 9.94522 -5 783 | vertex 1.04528 9.94522 -5 784 | endloop 785 | endfacet 786 | facet normal 0 0 -1 787 | outer loop 788 | vertex -6.69131 -7.43145 -5 789 | vertex 0.546309 -5.19779 -5 790 | vertex -5 -8.66025 -5 791 | endloop 792 | endfacet 793 | facet normal 0 0 -1 794 | outer loop 795 | vertex -8.09017 -5.87785 -5 796 | vertex 0.546309 -5.19779 -5 797 | vertex -6.69131 -7.43145 -5 798 | endloop 799 | endfacet 800 | facet normal 0 0 -1 801 | outer loop 802 | vertex 0.546309 5.19779 -5 803 | vertex -3.09017 9.51056 -5 804 | vertex -1.04528 9.94522 -5 805 | endloop 806 | endfacet 807 | facet normal 0 0 -1 808 | outer loop 809 | vertex 0.546309 5.19779 -5 810 | vertex -5 8.66025 -5 811 | vertex -3.09017 9.51056 -5 812 | endloop 813 | endfacet 814 | facet normal -0 0 -1 815 | outer loop 816 | vertex 0.546309 -5.19779 -5 817 | vertex -8.09017 -5.87785 -5 818 | vertex 0 0 -5 819 | endloop 820 | endfacet 821 | facet normal 0 0 -1 822 | outer loop 823 | vertex -9.13545 -4.06737 -5 824 | vertex 0 0 -5 825 | vertex -8.09017 -5.87785 -5 826 | endloop 827 | endfacet 828 | facet normal 0 0 -1 829 | outer loop 830 | vertex 0.546309 5.19779 -5 831 | vertex -6.69131 7.43145 -5 832 | vertex -5 8.66025 -5 833 | endloop 834 | endfacet 835 | facet normal 0 0 -1 836 | outer loop 837 | vertex -9.78148 -2.07912 -5 838 | vertex 0 0 -5 839 | vertex -9.13545 -4.06737 -5 840 | endloop 841 | endfacet 842 | facet normal 0 0 -1 843 | outer loop 844 | vertex 0.546309 5.19779 -5 845 | vertex -8.09017 5.87785 -5 846 | vertex -6.69131 7.43145 -5 847 | endloop 848 | endfacet 849 | facet normal 0 0 -1 850 | outer loop 851 | vertex -10 0 -5 852 | vertex 0 0 -5 853 | vertex -9.78148 -2.07912 -5 854 | endloop 855 | endfacet 856 | facet normal 0 0 -1 857 | outer loop 858 | vertex 0 0 -5 859 | vertex -8.09017 5.87785 -5 860 | vertex 0.546309 5.19779 -5 861 | endloop 862 | endfacet 863 | facet normal 0 -0 -1 864 | outer loop 865 | vertex -9.78148 2.07912 -5 866 | vertex 0 0 -5 867 | vertex -10 0 -5 868 | endloop 869 | endfacet 870 | facet normal 0 -0 -1 871 | outer loop 872 | vertex -8.09017 5.87785 -5 873 | vertex 0 0 -5 874 | vertex -9.13545 4.06737 -5 875 | endloop 876 | endfacet 877 | facet normal 0 -0 -1 878 | outer loop 879 | vertex -9.13545 4.06737 -5 880 | vertex 0 0 -5 881 | vertex -9.78148 2.07912 -5 882 | endloop 883 | endfacet 884 | facet normal -0.587785 -0.809017 0 885 | outer loop 886 | vertex -6.69131 -7.43145 -5 887 | vertex -5 -8.66025 5 888 | vertex -6.69131 -7.43145 5 889 | endloop 890 | endfacet 891 | facet normal -0.587785 -0.809017 -0 892 | outer loop 893 | vertex -5 -8.66025 5 894 | vertex -6.69131 -7.43145 -5 895 | vertex -5 -8.66025 -5 896 | endloop 897 | endfacet 898 | facet normal 0.951057 -0.309017 0 899 | outer loop 900 | vertex 0.546309 5.19779 5 901 | vertex 2.02143 9.73773 -5 902 | vertex 2.02143 9.73773 5 903 | endloop 904 | endfacet 905 | facet normal 0.951057 -0.309017 0 906 | outer loop 907 | vertex 2.02143 9.73773 -5 908 | vertex 0.546309 5.19779 5 909 | vertex 0.546309 5.19779 -5 910 | endloop 911 | endfacet 912 | facet normal 0.994522 -0.104528 0 913 | outer loop 914 | vertex 0 0 5 915 | vertex 0.546309 5.19779 -5 916 | vertex 0.546309 5.19779 5 917 | endloop 918 | endfacet 919 | facet normal 0.994522 -0.104528 0 920 | outer loop 921 | vertex 0.546309 5.19779 -5 922 | vertex 0 0 5 923 | vertex 0 0 -5 924 | endloop 925 | endfacet 926 | facet normal 0.951057 0.309017 0 927 | outer loop 928 | vertex 2.02143 -9.73773 5 929 | vertex 0.546309 -5.19779 -5 930 | vertex 0.546309 -5.19779 5 931 | endloop 932 | endfacet 933 | facet normal 0.951057 0.309017 0 934 | outer loop 935 | vertex 0.546309 -5.19779 -5 936 | vertex 2.02143 -9.73773 5 937 | vertex 2.02143 -9.73773 -5 938 | endloop 939 | endfacet 940 | facet normal 0.994522 0.104528 0 941 | outer loop 942 | vertex 0.546309 -5.19779 5 943 | vertex 0 0 -5 944 | vertex 0 0 5 945 | endloop 946 | endfacet 947 | facet normal 0.994522 0.104528 0 948 | outer loop 949 | vertex 0 0 -5 950 | vertex 0.546309 -5.19779 5 951 | vertex 0.546309 -5.19779 -5 952 | endloop 953 | endfacet 954 | facet normal 0 0.994522 0.104527 955 | outer loop 956 | vertex -8.65594 4.8979 0.971369 957 | vertex -18 4.89074 1.03956 958 | vertex -8.66008 4.89074 1.03956 959 | endloop 960 | endfacet 961 | facet normal 1.45277e-08 0.994522 0.104529 962 | outer loop 963 | vertex -18 4.89074 1.03956 964 | vertex -8.65594 4.8979 0.971369 965 | vertex -18 5 0 966 | endloop 967 | endfacet 968 | facet normal 1.00867e-07 0.994522 0.104528 969 | outer loop 970 | vertex -8.597 5 0 971 | vertex -18 5 0 972 | vertex -8.65594 4.8979 0.971369 973 | endloop 974 | endfacet 975 | facet normal 0 0 1 976 | outer loop 977 | vertex -9.94507 0.522642 4.97261 978 | vertex -18 0.522642 4.97261 979 | vertex -10 0 4.97261 980 | endloop 981 | endfacet 982 | facet normal 0 0 1 983 | outer loop 984 | vertex -18 -0.522642 4.97261 985 | vertex -10 0 4.97261 986 | vertex -18 0.522642 4.97261 987 | endloop 988 | endfacet 989 | facet normal 0 0 1 990 | outer loop 991 | vertex -10 0 4.97261 992 | vertex -18 -0.522642 4.97261 993 | vertex -9.94507 -0.522642 4.97261 994 | endloop 995 | endfacet 996 | facet normal 0 -0.207911 -0.978148 997 | outer loop 998 | vertex -18 -1.54508 -4.75528 999 | vertex -9.94507 -0.522642 -4.97261 1000 | vertex -9.8376 -1.54508 -4.75528 1001 | endloop 1002 | endfacet 1003 | facet normal -0 -0.207911 -0.978148 1004 | outer loop 1005 | vertex -9.94507 -0.522642 -4.97261 1006 | vertex -18 -1.54508 -4.75528 1007 | vertex -18 -0.522642 -4.97261 1008 | endloop 1009 | endfacet 1010 | facet normal 5.03175e-08 0.587785 0.809017 1011 | outer loop 1012 | vertex -9.40866 3.22653 3.80227 1013 | vertex -18 2.5 4.33013 1014 | vertex -9.64472 2.5 4.33013 1015 | endloop 1016 | endfacet 1017 | facet normal 1.02223e-07 0.406737 0.913545 1018 | outer loop 1019 | vertex -18 2.5 4.33013 1020 | vertex -9.8376 1.54508 4.75528 1021 | vertex -9.81934 1.71882 4.67793 1022 | endloop 1023 | endfacet 1024 | facet normal 0 0.406737 0.913545 1025 | outer loop 1026 | vertex -9.8376 1.54508 4.75528 1027 | vertex -18 2.5 4.33013 1028 | vertex -18 1.54508 4.75528 1029 | endloop 1030 | endfacet 1031 | facet normal -0 0.587786 0.809017 1032 | outer loop 1033 | vertex -18 3.34565 3.71572 1034 | vertex -9.40866 3.22653 3.80227 1035 | vertex -9.36995 3.34565 3.71572 1036 | endloop 1037 | endfacet 1038 | facet normal -3.78745e-09 0.587785 0.809017 1039 | outer loop 1040 | vertex -9.40866 3.22653 3.80227 1041 | vertex -18 3.34565 3.71572 1042 | vertex -18 2.5 4.33013 1043 | endloop 1044 | endfacet 1045 | facet normal 0 -0.994522 0.104529 1046 | outer loop 1047 | vertex -8.66008 -4.89074 1.03956 1048 | vertex -18 -4.89074 1.03956 1049 | vertex -8.60079 -4.99344 0.0624554 1050 | endloop 1051 | endfacet 1052 | facet normal 0 -0.866025 -0.5 1053 | outer loop 1054 | vertex -18 -4.56773 -2.03368 1055 | vertex -9.13545 -4.06737 -2.90033 1056 | vertex -8.84657 -4.56773 -2.03368 1057 | endloop 1058 | endfacet 1059 | facet normal -0 -0.866025 -0.5 1060 | outer loop 1061 | vertex -9.14269 -4.04508 -2.93893 1062 | vertex -18 -4.56773 -2.03368 1063 | vertex -18 -4.04508 -2.93893 1064 | endloop 1065 | endfacet 1066 | facet normal 1.09819e-07 -0.866026 -0.499999 1067 | outer loop 1068 | vertex -18 -4.56773 -2.03368 1069 | vertex -9.14269 -4.04508 -2.93893 1070 | vertex -9.13545 -4.06737 -2.90033 1071 | endloop 1072 | endfacet 1073 | facet normal 0 -0.866025 0.5 1074 | outer loop 1075 | vertex -18 -4.56773 2.03368 1076 | vertex -9.14269 -4.04508 2.93893 1077 | vertex -18 -4.04508 2.93893 1078 | endloop 1079 | endfacet 1080 | facet normal 1.09819e-07 -0.866026 0.499999 1081 | outer loop 1082 | vertex -9.14269 -4.04508 2.93893 1083 | vertex -18 -4.56773 2.03368 1084 | vertex -9.13545 -4.06737 2.90033 1085 | endloop 1086 | endfacet 1087 | facet normal 0 -0.866025 0.5 1088 | outer loop 1089 | vertex -9.13545 -4.06737 2.90033 1090 | vertex -18 -4.56773 2.03368 1091 | vertex -8.84657 -4.56773 2.03368 1092 | endloop 1093 | endfacet 1094 | facet normal -5.03175e-08 -0.587785 0.809017 1095 | outer loop 1096 | vertex -18 -3.34565 3.71572 1097 | vertex -9.64472 -2.5 4.33013 1098 | vertex -18 -2.5 4.33013 1099 | endloop 1100 | endfacet 1101 | facet normal 2.78279e-08 -0.587785 0.809017 1102 | outer loop 1103 | vertex -9.64472 -2.5 4.33013 1104 | vertex -18 -3.34565 3.71572 1105 | vertex -9.60074 -2.63537 4.23178 1106 | endloop 1107 | endfacet 1108 | facet normal -0 0.207911 0.978148 1109 | outer loop 1110 | vertex -18 1.54508 4.75528 1111 | vertex -9.94507 0.522642 4.97261 1112 | vertex -9.8376 1.54508 4.75528 1113 | endloop 1114 | endfacet 1115 | facet normal 0 0.207911 0.978148 1116 | outer loop 1117 | vertex -9.94507 0.522642 4.97261 1118 | vertex -18 1.54508 4.75528 1119 | vertex -18 0.522642 4.97261 1120 | endloop 1121 | endfacet 1122 | facet normal 1.09819e-07 0.866026 0.499999 1123 | outer loop 1124 | vertex -18 4.56773 2.03368 1125 | vertex -9.14269 4.04508 2.93893 1126 | vertex -9.13545 4.06737 2.90033 1127 | endloop 1128 | endfacet 1129 | facet normal -0 0.866025 0.5 1130 | outer loop 1131 | vertex -18 4.56773 2.03368 1132 | vertex -9.13545 4.06737 2.90033 1133 | vertex -8.84657 4.56773 2.03368 1134 | endloop 1135 | endfacet 1136 | facet normal 0 0.866025 0.5 1137 | outer loop 1138 | vertex -9.14269 4.04508 2.93893 1139 | vertex -18 4.56773 2.03368 1140 | vertex -18 4.04508 2.93893 1141 | endloop 1142 | endfacet 1143 | facet normal -0 -0.743145 -0.669131 1144 | outer loop 1145 | vertex -9.36995 -3.34565 -3.71572 1146 | vertex -18 -4.04508 -2.93893 1147 | vertex -18 -3.34565 -3.71572 1148 | endloop 1149 | endfacet 1150 | facet normal 0 -0.743145 -0.669131 1151 | outer loop 1152 | vertex -18 -4.04508 -2.93893 1153 | vertex -9.36995 -3.34565 -3.71572 1154 | vertex -9.14269 -4.04508 -2.93893 1155 | endloop 1156 | endfacet 1157 | facet normal 5.03175e-08 0.587785 -0.809017 1158 | outer loop 1159 | vertex -9.64472 2.5 -4.33013 1160 | vertex -18 2.5 -4.33013 1161 | vertex -9.40866 3.22653 -3.80227 1162 | endloop 1163 | endfacet 1164 | facet normal 1.00867e-07 0.994522 -0.104528 1165 | outer loop 1166 | vertex -8.65594 4.8979 -0.971369 1167 | vertex -18 5 0 1168 | vertex -8.597 5 0 1169 | endloop 1170 | endfacet 1171 | facet normal -0 0.743145 0.669131 1172 | outer loop 1173 | vertex -18 4.04508 2.93893 1174 | vertex -9.36995 3.34565 3.71572 1175 | vertex -9.14269 4.04508 2.93893 1176 | endloop 1177 | endfacet 1178 | facet normal 0 0.743145 0.669131 1179 | outer loop 1180 | vertex -9.36995 3.34565 3.71572 1181 | vertex -18 4.04508 2.93893 1182 | vertex -18 3.34565 3.71572 1183 | endloop 1184 | endfacet 1185 | facet normal -0 0.951057 0.309017 1186 | outer loop 1187 | vertex -18 4.89074 1.03956 1188 | vertex -8.84657 4.56773 2.03368 1189 | vertex -8.66008 4.89074 1.03956 1190 | endloop 1191 | endfacet 1192 | facet normal 0 0.951057 0.309017 1193 | outer loop 1194 | vertex -8.84657 4.56773 2.03368 1195 | vertex -18 4.89074 1.03956 1196 | vertex -18 4.56773 2.03368 1197 | endloop 1198 | endfacet 1199 | facet normal 7.3614e-08 0.406737 0.913545 1200 | outer loop 1201 | vertex -9.78148 2.07912 4.51752 1202 | vertex -18 2.5 4.33013 1203 | vertex -9.81934 1.71882 4.67793 1204 | endloop 1205 | endfacet 1206 | facet normal 3.48188e-08 0.406737 0.913546 1207 | outer loop 1208 | vertex -18 2.5 4.33013 1209 | vertex -9.78148 2.07912 4.51752 1210 | vertex -9.64472 2.5 4.33013 1211 | endloop 1212 | endfacet 1213 | facet normal 0 -0.951057 0.309017 1214 | outer loop 1215 | vertex -18 -4.89074 1.03956 1216 | vertex -8.84657 -4.56773 2.03368 1217 | vertex -18 -4.56773 2.03368 1218 | endloop 1219 | endfacet 1220 | facet normal 0 -0.951057 0.309017 1221 | outer loop 1222 | vertex -8.84657 -4.56773 2.03368 1223 | vertex -18 -4.89074 1.03956 1224 | vertex -8.66008 -4.89074 1.03956 1225 | endloop 1226 | endfacet 1227 | facet normal 0 -0.587785 0.809017 1228 | outer loop 1229 | vertex -9.60074 -2.63537 4.23178 1230 | vertex -18 -3.34565 3.71572 1231 | vertex -9.36995 -3.34565 3.71572 1232 | endloop 1233 | endfacet 1234 | facet normal 4.43482e-09 -0.406737 0.913546 1235 | outer loop 1236 | vertex -9.78148 -2.07912 4.51752 1237 | vertex -18 -1.54508 4.75528 1238 | vertex -9.69739 -2.33791 4.40229 1239 | endloop 1240 | endfacet 1241 | facet normal 0 -0.406737 0.913545 1242 | outer loop 1243 | vertex -18 -1.54508 4.75528 1244 | vertex -9.78148 -2.07912 4.51752 1245 | vertex -9.8376 -1.54508 4.75528 1246 | endloop 1247 | endfacet 1248 | facet normal 0 -0.207911 0.978148 1249 | outer loop 1250 | vertex -18 -1.54508 4.75528 1251 | vertex -9.94507 -0.522642 4.97261 1252 | vertex -18 -0.522642 4.97261 1253 | endloop 1254 | endfacet 1255 | facet normal 0 -0.207911 0.978148 1256 | outer loop 1257 | vertex -9.94507 -0.522642 4.97261 1258 | vertex -18 -1.54508 4.75528 1259 | vertex -9.8376 -1.54508 4.75528 1260 | endloop 1261 | endfacet 1262 | facet normal -1.1763e-07 -0.994522 0.104528 1263 | outer loop 1264 | vertex -18 -5 0 1265 | vertex -8.60079 -4.99344 0.0624554 1266 | vertex -18 -4.89074 1.03956 1267 | endloop 1268 | endfacet 1269 | facet normal -1.00867e-07 -0.994522 0.104526 1270 | outer loop 1271 | vertex -8.60079 -4.99344 0.0624554 1272 | vertex -18 -5 0 1273 | vertex -8.597 -5 0 1274 | endloop 1275 | endfacet 1276 | facet normal 0 -0.406737 -0.913545 1277 | outer loop 1278 | vertex -18 -2.5 -4.33013 1279 | vertex -9.78148 -2.07912 -4.51752 1280 | vertex -9.64472 -2.5 -4.33013 1281 | endloop 1282 | endfacet 1283 | facet normal -1.56413e-08 -0.406737 -0.913545 1284 | outer loop 1285 | vertex -18 -2.5 -4.33013 1286 | vertex -9.8376 -1.54508 -4.75528 1287 | vertex -9.78148 -2.07912 -4.51752 1288 | endloop 1289 | endfacet 1290 | facet normal -0 -0.406737 -0.913545 1291 | outer loop 1292 | vertex -9.8376 -1.54508 -4.75528 1293 | vertex -18 -2.5 -4.33013 1294 | vertex -18 -1.54508 -4.75528 1295 | endloop 1296 | endfacet 1297 | facet normal 0 0.406737 -0.913545 1298 | outer loop 1299 | vertex -18 1.54508 -4.75528 1300 | vertex -9.81934 1.71882 -4.67793 1301 | vertex -9.8376 1.54508 -4.75528 1302 | endloop 1303 | endfacet 1304 | facet normal 1.28576e-08 0.406737 -0.913545 1305 | outer loop 1306 | vertex -9.81934 1.71882 -4.67793 1307 | vertex -18 1.54508 -4.75528 1308 | vertex -18 2.5 -4.33013 1309 | endloop 1310 | endfacet 1311 | facet normal 3.48188e-08 0.406737 -0.913546 1312 | outer loop 1313 | vertex -9.78148 2.07912 -4.51752 1314 | vertex -18 2.5 -4.33013 1315 | vertex -9.64472 2.5 -4.33013 1316 | endloop 1317 | endfacet 1318 | facet normal 8.04688e-08 0.406737 -0.913545 1319 | outer loop 1320 | vertex -18 2.5 -4.33013 1321 | vertex -9.78148 2.07912 -4.51752 1322 | vertex -9.81934 1.71882 -4.67793 1323 | endloop 1324 | endfacet 1325 | facet normal 0 -0.587785 -0.809017 1326 | outer loop 1327 | vertex -18 -3.34565 -3.71572 1328 | vertex -9.64472 -2.5 -4.33013 1329 | vertex -9.36995 -3.34565 -3.71572 1330 | endloop 1331 | endfacet 1332 | facet normal -0 -0.587785 -0.809017 1333 | outer loop 1334 | vertex -9.64472 -2.5 -4.33013 1335 | vertex -18 -3.34565 -3.71572 1336 | vertex -18 -2.5 -4.33013 1337 | endloop 1338 | endfacet 1339 | facet normal 0 0.866025 -0.5 1340 | outer loop 1341 | vertex -9.13545 4.06737 -2.90033 1342 | vertex -18 4.56773 -2.03368 1343 | vertex -8.84657 4.56773 -2.03368 1344 | endloop 1345 | endfacet 1346 | facet normal 1.09819e-07 0.866026 -0.499999 1347 | outer loop 1348 | vertex -9.14269 4.04508 -2.93893 1349 | vertex -18 4.56773 -2.03368 1350 | vertex -9.13545 4.06737 -2.90033 1351 | endloop 1352 | endfacet 1353 | facet normal 0 0.866025 -0.5 1354 | outer loop 1355 | vertex -18 4.56773 -2.03368 1356 | vertex -9.14269 4.04508 -2.93893 1357 | vertex -18 4.04508 -2.93893 1358 | endloop 1359 | endfacet 1360 | facet normal 0 -0.743145 0.669131 1361 | outer loop 1362 | vertex -18 -4.04508 2.93893 1363 | vertex -9.36995 -3.34565 3.71572 1364 | vertex -18 -3.34565 3.71572 1365 | endloop 1366 | endfacet 1367 | facet normal 0 -0.743145 0.669131 1368 | outer loop 1369 | vertex -9.36995 -3.34565 3.71572 1370 | vertex -18 -4.04508 2.93893 1371 | vertex -9.14269 -4.04508 2.93893 1372 | endloop 1373 | endfacet 1374 | facet normal -5.37959e-08 -0.406737 0.913545 1375 | outer loop 1376 | vertex -18 -2.5 4.33013 1377 | vertex -9.69739 -2.33791 4.40229 1378 | vertex -18 -1.54508 4.75528 1379 | endloop 1380 | endfacet 1381 | facet normal -3.48189e-08 -0.406738 0.913545 1382 | outer loop 1383 | vertex -9.69739 -2.33791 4.40229 1384 | vertex -18 -2.5 4.33013 1385 | vertex -9.64472 -2.5 4.33013 1386 | endloop 1387 | endfacet 1388 | facet normal -1 0 0 1389 | outer loop 1390 | vertex -18 4.89074 -1.03956 1391 | vertex -18 4.89074 1.03956 1392 | vertex -18 5 0 1393 | endloop 1394 | endfacet 1395 | facet normal -1 0 0 1396 | outer loop 1397 | vertex -18 4.56773 -2.03368 1398 | vertex -18 4.89074 1.03956 1399 | vertex -18 4.89074 -1.03956 1400 | endloop 1401 | endfacet 1402 | facet normal -1 0 0 1403 | outer loop 1404 | vertex -18 4.56773 -2.03368 1405 | vertex -18 4.56773 2.03368 1406 | vertex -18 4.89074 1.03956 1407 | endloop 1408 | endfacet 1409 | facet normal -1 0 0 1410 | outer loop 1411 | vertex -18 4.04508 -2.93893 1412 | vertex -18 4.56773 2.03368 1413 | vertex -18 4.56773 -2.03368 1414 | endloop 1415 | endfacet 1416 | facet normal -1 0 0 1417 | outer loop 1418 | vertex -18 4.04508 -2.93893 1419 | vertex -18 4.04508 2.93893 1420 | vertex -18 4.56773 2.03368 1421 | endloop 1422 | endfacet 1423 | facet normal -1 0 0 1424 | outer loop 1425 | vertex -18 3.34565 -3.71572 1426 | vertex -18 4.04508 2.93893 1427 | vertex -18 4.04508 -2.93893 1428 | endloop 1429 | endfacet 1430 | facet normal -1 0 0 1431 | outer loop 1432 | vertex -18 3.34565 -3.71572 1433 | vertex -18 3.34565 3.71572 1434 | vertex -18 4.04508 2.93893 1435 | endloop 1436 | endfacet 1437 | facet normal -1 0 0 1438 | outer loop 1439 | vertex -18 2.5 -4.33013 1440 | vertex -18 3.34565 3.71572 1441 | vertex -18 3.34565 -3.71572 1442 | endloop 1443 | endfacet 1444 | facet normal -1 0 0 1445 | outer loop 1446 | vertex -18 2.5 -4.33013 1447 | vertex -18 2.5 4.33013 1448 | vertex -18 3.34565 3.71572 1449 | endloop 1450 | endfacet 1451 | facet normal -1 0 0 1452 | outer loop 1453 | vertex -18 1.54508 -4.75528 1454 | vertex -18 2.5 4.33013 1455 | vertex -18 2.5 -4.33013 1456 | endloop 1457 | endfacet 1458 | facet normal -1 0 0 1459 | outer loop 1460 | vertex -18 1.54508 -4.75528 1461 | vertex -18 1.54508 4.75528 1462 | vertex -18 2.5 4.33013 1463 | endloop 1464 | endfacet 1465 | facet normal -1 0 0 1466 | outer loop 1467 | vertex -18 0.522642 -4.97261 1468 | vertex -18 1.54508 4.75528 1469 | vertex -18 1.54508 -4.75528 1470 | endloop 1471 | endfacet 1472 | facet normal -1 0 0 1473 | outer loop 1474 | vertex -18 0.522642 -4.97261 1475 | vertex -18 0.522642 4.97261 1476 | vertex -18 1.54508 4.75528 1477 | endloop 1478 | endfacet 1479 | facet normal -1 0 0 1480 | outer loop 1481 | vertex -18 -0.522642 -4.97261 1482 | vertex -18 0.522642 4.97261 1483 | vertex -18 0.522642 -4.97261 1484 | endloop 1485 | endfacet 1486 | facet normal -1 0 0 1487 | outer loop 1488 | vertex -18 -0.522642 -4.97261 1489 | vertex -18 -0.522642 4.97261 1490 | vertex -18 0.522642 4.97261 1491 | endloop 1492 | endfacet 1493 | facet normal -1 0 0 1494 | outer loop 1495 | vertex -18 -1.54508 -4.75528 1496 | vertex -18 -0.522642 4.97261 1497 | vertex -18 -0.522642 -4.97261 1498 | endloop 1499 | endfacet 1500 | facet normal -1 0 0 1501 | outer loop 1502 | vertex -18 -1.54508 -4.75528 1503 | vertex -18 -1.54508 4.75528 1504 | vertex -18 -0.522642 4.97261 1505 | endloop 1506 | endfacet 1507 | facet normal -1 0 0 1508 | outer loop 1509 | vertex -18 -1.54508 -4.75528 1510 | vertex -18 -2.5 4.33013 1511 | vertex -18 -1.54508 4.75528 1512 | endloop 1513 | endfacet 1514 | facet normal -1 0 0 1515 | outer loop 1516 | vertex -18 -2.5 -4.33013 1517 | vertex -18 -2.5 4.33013 1518 | vertex -18 -1.54508 -4.75528 1519 | endloop 1520 | endfacet 1521 | facet normal -1 0 0 1522 | outer loop 1523 | vertex -18 -3.34565 -3.71572 1524 | vertex -18 -2.5 4.33013 1525 | vertex -18 -2.5 -4.33013 1526 | endloop 1527 | endfacet 1528 | facet normal -1 0 0 1529 | outer loop 1530 | vertex -18 -3.34565 -3.71572 1531 | vertex -18 -3.34565 3.71572 1532 | vertex -18 -2.5 4.33013 1533 | endloop 1534 | endfacet 1535 | facet normal -1 0 0 1536 | outer loop 1537 | vertex -18 -4.04508 -2.93893 1538 | vertex -18 -3.34565 3.71572 1539 | vertex -18 -3.34565 -3.71572 1540 | endloop 1541 | endfacet 1542 | facet normal -1 0 0 1543 | outer loop 1544 | vertex -18 -4.04508 -2.93893 1545 | vertex -18 -4.04508 2.93893 1546 | vertex -18 -3.34565 3.71572 1547 | endloop 1548 | endfacet 1549 | facet normal -1 0 0 1550 | outer loop 1551 | vertex -18 -4.56773 -2.03368 1552 | vertex -18 -4.04508 2.93893 1553 | vertex -18 -4.04508 -2.93893 1554 | endloop 1555 | endfacet 1556 | facet normal -1 0 0 1557 | outer loop 1558 | vertex -18 -4.56773 -2.03368 1559 | vertex -18 -4.56773 2.03368 1560 | vertex -18 -4.04508 2.93893 1561 | endloop 1562 | endfacet 1563 | facet normal -1 0 0 1564 | outer loop 1565 | vertex -18 -4.89074 -1.03956 1566 | vertex -18 -4.56773 2.03368 1567 | vertex -18 -4.56773 -2.03368 1568 | endloop 1569 | endfacet 1570 | facet normal -1 0 0 1571 | outer loop 1572 | vertex -18 -4.89074 -1.03956 1573 | vertex -18 -4.89074 1.03956 1574 | vertex -18 -4.56773 2.03368 1575 | endloop 1576 | endfacet 1577 | facet normal -1 0 -0 1578 | outer loop 1579 | vertex -18 -4.89074 1.03956 1580 | vertex -18 -4.89074 -1.03956 1581 | vertex -18 -5 0 1582 | endloop 1583 | endfacet 1584 | facet normal -1.00867e-07 -0.994522 -0.104526 1585 | outer loop 1586 | vertex -18 -5 0 1587 | vertex -8.60079 -4.99344 -0.0624554 1588 | vertex -8.597 -5 0 1589 | endloop 1590 | endfacet 1591 | facet normal -1.1763e-07 -0.994522 -0.104528 1592 | outer loop 1593 | vertex -8.60079 -4.99344 -0.0624554 1594 | vertex -18 -5 0 1595 | vertex -18 -4.89074 -1.03956 1596 | endloop 1597 | endfacet 1598 | facet normal 0 0 -1 1599 | outer loop 1600 | vertex -9.94507 -0.522642 -4.97261 1601 | vertex -18 -0.522642 -4.97261 1602 | vertex -10 0 -4.97261 1603 | endloop 1604 | endfacet 1605 | facet normal 0 0 -1 1606 | outer loop 1607 | vertex -18 0.522642 -4.97261 1608 | vertex -10 0 -4.97261 1609 | vertex -18 -0.522642 -4.97261 1610 | endloop 1611 | endfacet 1612 | facet normal 0 0 -1 1613 | outer loop 1614 | vertex -10 0 -4.97261 1615 | vertex -18 0.522642 -4.97261 1616 | vertex -9.94507 0.522642 -4.97261 1617 | endloop 1618 | endfacet 1619 | facet normal 0 0.994522 -0.104527 1620 | outer loop 1621 | vertex -18 4.89074 -1.03956 1622 | vertex -8.65594 4.8979 -0.971369 1623 | vertex -8.66008 4.89074 -1.03956 1624 | endloop 1625 | endfacet 1626 | facet normal 1.45277e-08 0.994522 -0.104529 1627 | outer loop 1628 | vertex -8.65594 4.8979 -0.971369 1629 | vertex -18 4.89074 -1.03956 1630 | vertex -18 5 0 1631 | endloop 1632 | endfacet 1633 | facet normal 0 0.951057 -0.309017 1634 | outer loop 1635 | vertex -8.84657 4.56773 -2.03368 1636 | vertex -18 4.89074 -1.03956 1637 | vertex -8.66008 4.89074 -1.03956 1638 | endloop 1639 | endfacet 1640 | facet normal 0 0.951057 -0.309017 1641 | outer loop 1642 | vertex -18 4.89074 -1.03956 1643 | vertex -8.84657 4.56773 -2.03368 1644 | vertex -18 4.56773 -2.03368 1645 | endloop 1646 | endfacet 1647 | facet normal 0 0.743145 -0.669131 1648 | outer loop 1649 | vertex -9.36995 3.34565 -3.71572 1650 | vertex -18 4.04508 -2.93893 1651 | vertex -9.14269 4.04508 -2.93893 1652 | endloop 1653 | endfacet 1654 | facet normal 0 0.743145 -0.669131 1655 | outer loop 1656 | vertex -18 4.04508 -2.93893 1657 | vertex -9.36995 3.34565 -3.71572 1658 | vertex -18 3.34565 -3.71572 1659 | endloop 1660 | endfacet 1661 | facet normal 1.25242e-08 0.587785 -0.809017 1662 | outer loop 1663 | vertex -18 3.34565 -3.71572 1664 | vertex -9.40866 3.22653 -3.80227 1665 | vertex -18 2.5 -4.33013 1666 | endloop 1667 | endfacet 1668 | facet normal 0 0.587785 -0.809017 1669 | outer loop 1670 | vertex -9.40866 3.22653 -3.80227 1671 | vertex -18 3.34565 -3.71572 1672 | vertex -9.36995 3.34565 -3.71572 1673 | endloop 1674 | endfacet 1675 | facet normal 0 -0.994522 -0.104529 1676 | outer loop 1677 | vertex -8.60079 -4.99344 -0.0624554 1678 | vertex -18 -4.89074 -1.03956 1679 | vertex -8.66008 -4.89074 -1.03956 1680 | endloop 1681 | endfacet 1682 | facet normal -0 -0.951057 -0.309017 1683 | outer loop 1684 | vertex -8.84657 -4.56773 -2.03368 1685 | vertex -18 -4.89074 -1.03956 1686 | vertex -18 -4.56773 -2.03368 1687 | endloop 1688 | endfacet 1689 | facet normal 0 -0.951057 -0.309017 1690 | outer loop 1691 | vertex -18 -4.89074 -1.03956 1692 | vertex -8.84657 -4.56773 -2.03368 1693 | vertex -8.66008 -4.89074 -1.03956 1694 | endloop 1695 | endfacet 1696 | facet normal 0 0.207911 -0.978148 1697 | outer loop 1698 | vertex -18 1.54508 -4.75528 1699 | vertex -9.94507 0.522642 -4.97261 1700 | vertex -18 0.522642 -4.97261 1701 | endloop 1702 | endfacet 1703 | facet normal 0 0.207911 -0.978148 1704 | outer loop 1705 | vertex -9.94507 0.522642 -4.97261 1706 | vertex -18 1.54508 -4.75528 1707 | vertex -9.8376 1.54508 -4.75528 1708 | endloop 1709 | endfacet 1710 | endsolid OpenSCAD_Model 1711 | -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/files/Anemometer.scad: -------------------------------------------------------------------------------- 1 | //LTB Weather in 3D 2 | //Anemometer and Wind Direction 3 | 4 | $fn=30; 5 | //Non-Printable Extras 6 | //Neodymium Magnet, cylinder 2mm thick, 3mm diam 7 | //Red Switches, 14mm long 2mm diam 8 | //Thrust bearings, 8mm OD, 5 mmID, 2.5mm thick 9 | //Rods for the bearings 5mm OD, rescued brass antenna tubing is ideal! 10 | //Heat shrink tubing to make a small sleeve to adjust height off bearings 11 | 12 | //Make the shape of the front of the vane 13 | module prism(l, w, h){ 14 | polyhedron( 15 | points=[[0,0,0], [l,0,0], [l,w,0], [0,w,0], [0,w,h], [l,w,h]], 16 | faces=[[0,1,2,3],[5,4,3,2],[0,4,5,1],[0,3,4],[5,2,1]] 17 | ); 18 | } 19 | 20 | module windvane(){ 21 | difference(){ 22 | union(){ 23 | rotate([0,90,0]) cylinder(150,5,5,true); //main rod 24 | translate([-82.5,0,0])rotate([0,90,0]) cylinder(15,0,5,true); //pointy tip 25 | translate([45,-1,0]) cube([30,2,40]); //vane_1 26 | rotate([0,0,-90]) translate([-1,0,5]) prism(2,45, 35);//vane_2 27 | translate([0,0,-10]) cylinder(30,20,20,true); //mounting bracket 28 | } 29 | //This next dimension hollows the innner skirt of the windvane 30 | //It controls how close you can get the magnet to the reed switches 31 | //The magnet needs N-S to be vertical aligned with the reed switches 32 | //If it is not close enough or strong enough it will not reliably 33 | //trigger the both reed switches when positioned halfway between two. 34 | //This effect allows 16 directions to be obtained from 8 switches. 35 | //You may need to experiment a bit here to make it reliable. 36 | translate([0,0,-15]) cylinder(30,13.2,13.2,true); //mount cap inner 37 | cylinder(60,2.5,2.5,true); //mounting spindle axle hole 5mm diam 38 | //magnet mount, radial distance is adjustable for multiple reed 'hits' 39 | //hitting 2 reed switches at a time doubles resolution from 8 to 16 40 | translate([0,-11,-15]) rotate([0,0,90]) cube([20,3.1,2.6],true); 41 | } 42 | } 43 | 44 | module dirbasesupport(){ 45 | difference(){ 46 | union(){ 47 | translate([0,0,2.5]) cylinder(5,10,10,true); //axle mount top 48 | color("red") translate([0,0,-15]) cylinder(30,12,12,true); //mount cap inner 49 | translate([0,0,-39]) //move bottom skirt 50 | difference(){ 51 | color("red") cylinder(25,25,25,true); //outer skirt 52 | translate([0,0,-2]) cylinder(23,23,23,true); //inner skirt 53 | } 54 | } 55 | cylinder(70,3,3,true); //spindle hole,6mm ID for 5mm axle 56 | translate([0,0,3]) cylinder(4,4,4,true); //top hole for bearing 57 | translate([0,0,-28]) cylinder(4,4,4,true); //bottom hole for bearing 58 | rotate([0,0,22.5]) translate([7,0,-10]) cylinder(60,1,1,true);//Relay common wire 59 | rotate([90,180,22.5]) translate([-7,-5,0]) cylinder(6,1,1,true);//Relay common wire 60 | 61 | for(rrelay = [0 : 45 : 360]) 62 | //rotate([90,rrelay,0]) translate([25,10,0]) 63 | rotate([0,0,rrelay]) translate([9.5,0,-10]) cylinder(60,2,2,true);//Relays mounts 64 | } 65 | } 66 | 67 | //Print three of these separately 68 | module cup(){ 69 | color("blue") 70 | difference(){ 71 | translate([-66,0,0]) //radiate from center 72 | difference(){ 73 | union(){ 74 | sphere(20); //outer wall 75 | translate([35,0,5]) cube([50,10,10],true); //support arm 76 | } 77 | sphere(17); //inner space 78 | translate([0,0,-10]) cube([40,40,20],true); //chop off what we don't need 79 | } 80 | rotate([90,0,0]) translate([-10,5,0]) cylinder(20,1,1,true); //screw mount 81 | } 82 | } 83 | 84 | module cups3mount(){ 85 | difference(){ 86 | union(){ 87 | cylinder(20,20,20,true); 88 | translate([0,0,-19]) //move bottom skirt 89 | difference(){ 90 | cylinder(25,25,25,true); //outer skirt 91 | translate([0,0,-2]) cylinder(23,23,23,true); //inner skirt 92 | } 93 | } 94 | cups3(); //just used to create and align holes for cups 95 | rotate([0,0,174]) translate([-10,5,0]) cylinder(40,1.5,1.5,true); //screw mount 96 | rotate([0,0,54]) translate([-10,5,0]) cylinder(40,1.5,1.5,true); //screw mount 97 | rotate([0,0,294]) translate([-10,5,0]) cylinder(40,1.5,1.5,true); //screw mount 98 | cylinder(40,2.5,2.5,true);//spindle axle 5mm OD 99 | translate([0,-8,-10]) cube([2,3,4],true);//magnet hole, N-S is aligned tangential to circumference, ie magnetic force lines are along the switch reeds 100 | } 101 | } 102 | 103 | //now combine all three into one module, to set up holes in mount base 104 | module cups3(){ 105 | rotate([90,0,0])cup(); 106 | rotate([90,0,120])cup(); 107 | rotate([90,0,240])cup(); 108 | } 109 | 110 | module cuprotormount(){ 111 | difference(){ 112 | cylinder(30,20,20,true); 113 | rotate([0,0,54]) translate([-10,5,0]) cylinder(40,1.5,1.5,true); //reed relay mount 114 | rotate([0,0,294]) translate([-10,5,0]) cylinder(40,1.5,1.5,true); //reed relay mount 115 | rotate([0,90,57]) translate([-15,5.5,0]) cylinder(20,1.5,1.5,true); //reed relay slot for mounting 116 | 117 | cylinder(40,3,3,true);//6mm ID spindle bearing shaft, for a 5mm axle 118 | translate([0,0,14.5]) cylinder(2,4,4,true); //top hole for bearing 8mmOD 119 | translate([0,0,-14.5]) cylinder(2,4,4,true); //bottom hole for bearing 8mm OD 120 | } 121 | } 122 | 123 | //Glue this to the side of the speed indicator for a mouning option 124 | module bracketSpeed(){ 125 | difference(){ 126 | cylinder(10,10,10,true); 127 | translate([20,0,0]) cylinder(10,20,20,true); 128 | } 129 | translate([-13,0,0]) rotate([90,0,90,]) cylinder(10,5,5,true); 130 | } 131 | 132 | //Glue this to the side of the direction indicator for a mouning option 133 | module bracketDirection(){ 134 | difference(){ 135 | cylinder(10,10,10,true); 136 | translate([25,0,0]) cylinder(10,25,25,true); 137 | } 138 | translate([-13,0,0]) rotate([90,0,90,]) cylinder(10,5,5,true); 139 | } 140 | 141 | //Use this to mount the aluminium crossbar on a vertical aluminium tube 142 | module Tpiece(){ 143 | difference(){ 144 | union(){ 145 | cylinder(30,9,9,true); 146 | translate([-17,0,0]) rotate([90,0,90,]) cylinder(20,5.25,5.25,true); 147 | } 148 | translate([0,0,0]) cylinder(30,6.5,6.5,true); 149 | } 150 | } 151 | 152 | //Vertical mount for the aluminium tube onto the baseboard 153 | module Tframebase(){ 154 | difference(){ 155 | union(){ 156 | translate([0,0,2.5]) cylinder(5,20,20,true); 157 | translate([0,0,10]) cylinder(10,20,5.25,true); 158 | } 159 | rotate([0,0,0,]) cylinder(30,6.5,6.5,true); 160 | 161 | rotate([0,0,0]) translate([15,0,10]) cylinder(10,2,2,true); 162 | rotate([0,0,120]) translate([15,0,10])cylinder(10,2,2,true); 163 | rotate([0,0,240]) translate([15,0,10])cylinder(10,2,2,true); 164 | 165 | rotate([0,0,0]) translate([15,0,10]) cylinder(30,1,1,true); 166 | rotate([0,0,120]) translate([15,0,10])cylinder(30,1,1,true); 167 | rotate([0,0,240]) translate([15,0,10])cylinder(30,1,1,true); 168 | } 169 | } 170 | 171 | module direction(){ 172 | difference(){ 173 | union(){ 174 | translate([0,0,6]) windvane(); //direction indicator 175 | translate([0,0,0]) dirbasesupport(); //mount for direction indicator 176 | } 177 | //translate([-220,0,-200]) cube([400,400,400]); //shows cutaway 178 | } 179 | } 180 | 181 | module speed(){ 182 | //cup(); //one cup, print three times 183 | difference(){ 184 | union(){ 185 | cups3(); //three cups in place, DO NOT print this 186 | cups3mount(); //mount support for cups 187 | translate([0,0,-28]) color("gold") cuprotormount(); //speed base and bearings holder 188 | } 189 | //translate([-220,0,-200]) cube([400,400,400]); //shows cutaway 190 | } 191 | } 192 | 193 | //Rendering visually 194 | //Use these to see the parts "in-situ" 195 | 196 | //Wind Speed Parts 197 | translate([-60,0,0]) speed(); 198 | //translate([-20,0,0]) bracketSpeed(); 199 | 200 | //Wind Direction Parts 201 | //translate([60,0,0]) direction(); 202 | //translate([5,0,0]) bracketDirection(); 203 | 204 | //Mounting Frame Parts 205 | //Tpiece(); 206 | //Tframebase(); 207 | 208 | //STL List (render each separately and export as .stl) 209 | 210 | //Wind speed parts (Anemometer) 211 | //cup(); //print 3 of these 212 | //cups3mount(); 213 | //cuprotormount(); 214 | //bracketSpeed(); 215 | //Wind direction parts 216 | //windvane(); 217 | //dirbasesupport(); 218 | //bracketDirection(); 219 | //Frame parts 220 | //Tpiece(); 221 | //Tframebase(); -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/files/RainGuage.scad: -------------------------------------------------------------------------------- 1 | //LTB weather in 3D 2 | //Bucket tipping rain-guage 3 | 4 | //Non-Printable Extras 5 | //Neodymium Magnet, cylinder 2mm thick, 3mm diam 6 | //Red Switch, 14mm long 2mm diam 7 | //Rod for the axle 1.5 mm OD, rescued brass antenna tubing is ideal! 8 | //2 rings of plastic tubing to put on opposite ends of tipping bucket axle. 9 | 10 | $fn=60; 11 | hy=5; //hysteresis 12 | //Main support base for bucket, drainage and electronics 13 | module Rbase(){ 14 | difference(){ 15 | color("green") union(){ 16 | cylinder(4,50,50); //main base 17 | cylinder(8,45,45); //outer base rim 18 | translate([0,0,4]) cylinder(4,40,40); //main middle base 19 | translate([0,0,20]) cylinder(40,45,45,true); //main base outer cylinder 20 | } 21 | translate([0,0,25]) cylinder(40,43,43,true); //main base inner cylinder 22 | translate([30,26,0]) cylinder(20,2,2,true); //base mounting/levelling hole 23 | translate([-30,26,0]) cylinder(20,2,2,true); //base mounting/levelling hole 24 | translate([0,-40,0]) cylinder(20,2,2,true); //base mounting/levelling hole 25 | rotate([0,0,90]) cylinder(10,2.5,2.5,true); //small water drainhole 26 | translate([0,30,0]) rotate([0,0,90]) cylinder(10,2.5,2.5,true); //small wire exit hole 27 | translate([0,40,0]) rotate([0,90,90]) cylinder(20,2.5,2.5,true); //small wire exit tunnel 28 | } 29 | } 30 | module Rffsupport(){ 31 | color("blue") 32 | difference(){ 33 | translate([0,0,20]) cube([82.5,4,40],true); //side support 34 | translate([0,0,23+hy]) rotate([90,0,0]) cylinder(5,2,2,true);//locating semi-circle 35 | } 36 | } 37 | 38 | module drainramps(){ 39 | //drain the water our of the central hole 40 | color("yellow") translate([-23,0,8]) rotate([0,10,0])cube([39.5,30,1],true); 41 | color("yellow") translate([23,0,8]) rotate([0,-10,0])cube([39.5,30,1],true); 42 | //projections to stop lip of bucket being held by water tension 43 | color("red") translate([-38,0,11]) rotate([45,10,0])cube([10,2,2],true); 44 | color("red") translate([38,0,11]) rotate([45,-10,0])cube([10,2,2],true); 45 | 46 | } 47 | 48 | module Rrelaysupport(){ 49 | //place the reed switch in the gap and heat the wires on it to melt into the 50 | //plastic and hold it in place, or just glue it there. 51 | color("orange") 52 | difference(){ 53 | translate([0,30,50]) cube([30,4,20],true); //Plate for mounting reed switch 54 | translate([0,30,50]) rotate([0,90,0]) cube([15,5,3],true); //hole for reed switch 55 | } 56 | } 57 | 58 | module Rmainbase(){ 59 | difference(){ 60 | Rbase(); 61 | translate([0,0,30]) cube([82.4,124,40],true);//big cutaway 62 | } 63 | translate([0,-16,0]) Rffsupport(); 64 | translate([0,+16,0]) Rffsupport(); 65 | translate([0,-14,0]) Rrelaysupport(); 66 | drainramps(); 67 | } 68 | 69 | //Flip Flop tipping bucket 70 | module Rflipflop(){ 71 | difference(){ 72 | union(){ 73 | difference(){ 74 | //begin with 75 | translate([0,0,10]) color("red") cube([80,25,20],true); //main body 76 | //take these out 77 | translate([-20,0,35]) rotate([0,155,0]) cube([80,25,40],true); 78 | translate([20,0,35]) rotate([0,-155,0]) cube([80,25,40],true); //subtract top half of cube 79 | translate([0,0,10]) color("red") cube([80,23,20],true); //main body 80 | } 81 | //add these in 82 | cube([80,25,1],true); //the flat base of tipping cups 83 | color("gray") translate([0,0,8]) cube([2,25,25],true); //divider plate 84 | translate([0,0,-hy]) rotate([90,0,0]) cylinder(25,6,6,true); //outer axle bearing 85 | translate([0,13,-hy]) rotate([90,0,0]) cylinder(1,3,3,true); //washer A 86 | translate([0,-13,-hy]) rotate([90,0,0]) cylinder(1,3,3,true); //washer B 87 | translate([0,13,-hy]) rotate([90,0,0]) cylinder(1,3,5,true); //washer A slope 88 | translate([0,-13,-hy]) rotate([90,0,0]) cylinder(1,5,3,true); //washer B slope 89 | color("grey") translate([0,12,17]) rotate([0,90,0])cylinder(6,3,3,true); //support for the magnet 90 | } 91 | //take these out 92 | translate([0,0,-hy]) rotate([90,0,0]) cylinder(29,2,2,true); //inner axle 93 | translate([-5,12.5,12.5],true) cube([10,10,10]); //removes excess magnet support 94 | translate([0,12,17]) cube([4,3,2],true);//magnet hole, NB N-S is parallel to the reed switch, ie field lines run along the reed switches 95 | 96 | } 97 | } 98 | 99 | module funnel(){ 100 | translate([0,0,5]) 101 | difference(){ 102 | color("red") cylinder(90,50,50); //main base 103 | cylinder(90,45,45); //main base 104 | } 105 | difference(){ 106 | translate([0,0,55]) cylinder(40,2,48); 107 | translate([0,0,58]) cylinder(40,2,48); 108 | translate([0,0,55]) cylinder(10,2,2); 109 | } 110 | } 111 | 112 | //Main parts 113 | Rmainbase(); 114 | translate([0,0,38-hy]) rotate([0,0,0]) Rflipflop(); //flip flop tipping 115 | //Rflipflop(); 116 | difference(){ 117 | //funnel(); 118 | //uncomment for a "demonstration funnel" to show people how it works 119 | //rotate([0,0,90]) translate([10,-100,0]) cube([100,200,100]); //for demo cutaway 120 | } -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/0f729904a5f2e05334bc5dd88b66ae25_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/0f729904a5f2e05334bc5dd88b66ae25_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/117a4e0169dc935ad4cb069c9b1e4cbd_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/117a4e0169dc935ad4cb069c9b1e4cbd_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/15661ac53241d97e30403f3ccd07a3a0_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/15661ac53241d97e30403f3ccd07a3a0_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/19405cb05ae3fd27b113e646ea3810c1_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/19405cb05ae3fd27b113e646ea3810c1_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/2c7b42b0f8cd26165a07a06924028e5b_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/2c7b42b0f8cd26165a07a06924028e5b_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/2f4eb67d5eb4e4a115d83a93fdd548bd_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/2f4eb67d5eb4e4a115d83a93fdd548bd_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/3d7bd073ae92bd9a4f123ed83592e2da_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/3d7bd073ae92bd9a4f123ed83592e2da_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/4128c8499053c0b8ed6bece59226a6e4_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/4128c8499053c0b8ed6bece59226a6e4_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/45c1245175a171400667a6d880b7b2a3_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/45c1245175a171400667a6d880b7b2a3_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/5851a940cc2cf8ce6b7ae1dae2f9f374_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/5851a940cc2cf8ce6b7ae1dae2f9f374_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/665cde6034edafd1919697d14e3cbb7f_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/665cde6034edafd1919697d14e3cbb7f_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/6b7efd5bf7d866a3c7be1622005885e2_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/6b7efd5bf7d866a3c7be1622005885e2_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/6f4c261a202a8efb6d09fc4429fcd451_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/6f4c261a202a8efb6d09fc4429fcd451_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/6f54eee4d5941a1848efe295c70625fb_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/6f54eee4d5941a1848efe295c70625fb_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/7844c83e0afc9eee98446c4f50ffa83b_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/7844c83e0afc9eee98446c4f50ffa83b_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/7dec8525ebd62560725952abd26e961d_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/7dec8525ebd62560725952abd26e961d_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/80a48253a995d0b735cc264a9117a01e_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/80a48253a995d0b735cc264a9117a01e_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/8c24a9ce323ae254777e71005f5087d5_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/8c24a9ce323ae254777e71005f5087d5_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/9245b32cea09aa1bce04a988e750eaf5_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/9245b32cea09aa1bce04a988e750eaf5_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/a46b4e9dc1ee91424486a30a58d59f65_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/a46b4e9dc1ee91424486a30a58d59f65_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/aa5c15dc5b5677d0f9d4d23d35d61b8d_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/aa5c15dc5b5677d0f9d4d23d35d61b8d_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/abda42896f2a54828468f4c982fa79e0_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/abda42896f2a54828468f4c982fa79e0_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/b8ac2ffeab8d6cb9135d3699e298f246_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/b8ac2ffeab8d6cb9135d3699e298f246_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/c9b82732129711d131ec30678b11e9f1_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/c9b82732129711d131ec30678b11e9f1_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/e383737310d1c1f831bcede16474fa9f_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/e383737310d1c1f831bcede16474fa9f_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/ef46951516978715a64110eb92978627_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/ef46951516978715a64110eb92978627_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/f5733b1c9a6c24a76b0aa705a5f0eb99_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/f5733b1c9a6c24a76b0aa705a5f0eb99_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/LTB_Weather_Station/images/ff516d27357b673a9011a6b4d327566e_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/LTB_Weather_Station/images/ff516d27357b673a9011a6b4d327566e_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/Luftdaten_Stevensson_screen/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Luftdaten Stevensson screen (https://www.thingiverse.com/thing:2821592) by Naesstrom is licensed under the Creative Commons - Attribution license. 2 | http://creativecommons.org/licenses/by/3.0/ 3 | 4 | -------------------------------------------------------------------------------- /3DDruck/Luftdaten_Stevensson_screen/README.txt: -------------------------------------------------------------------------------- 1 | .: :, 2 | ,:::::::: ::` ::: ::: 3 | ,:::::::: ::` ::: ::: 4 | .,,:::,,, ::`.:, ... .. .:, .:. ..`... ..` .. .:, .. :: .::, .:,` 5 | ,:: ::::::: ::, ::::::: `:::::::.,:: ::: ::: .:::::: ::::: :::::: .:::::: 6 | ,:: :::::::: ::, :::::::: ::::::::.,:: ::: ::: :::,:::, ::::: ::::::, :::::::: 7 | ,:: ::: ::: ::, ::: :::`::. :::.,:: ::,`::`::: ::: ::: `::,` ::: ::: 8 | ,:: ::. ::: ::, ::` :::.:: ::.,:: :::::: ::::::::: ::` :::::: ::::::::: 9 | ,:: ::. ::: ::, ::` :::.:: ::.,:: .::::: ::::::::: ::` ::::::::::::::: 10 | ,:: ::. ::: ::, ::` ::: ::: `:::.,:: :::: :::` ,,, ::` .:: :::.::. ,,, 11 | ,:: ::. ::: ::, ::` ::: ::::::::.,:: :::: :::::::` ::` ::::::: :::::::. 12 | ,:: ::. ::: ::, ::` ::: :::::::`,:: ::. :::::` ::` :::::: :::::. 13 | ::, ,:: `` 14 | :::::::: 15 | :::::: 16 | `,,` 17 | 18 | 19 | https://www.thingiverse.com/thing:2821592 20 | Luftdaten Stevensson screen by Naesstrom is licensed under the Creative Commons - Attribution license. 21 | http://creativecommons.org/licenses/by/3.0/ 22 | 23 | # Summary 24 | 25 | #Luftdata? 26 | I'm part of a Swedish Citizen science projekt [luftdata.se](http://www.luftdata.se) measuring 27 | air particles using a sds011 sensor. It's a branch from the original german projekt [luftdaten.info](http://www.luftdaten.info) where you can read build instructions etc in English. 28 | 29 | __(You can of course also use the model to measure to other things then particle measurements, I've printed one identical where I have a BME280, BH1750 and a external tipping bucket for rain thus making my own weather station!)__ 30 | 31 | You can see a live map of all the particle readings [here](http://deutschland.maps.luftdaten.info/#4/51.67/20.23) 32 |
33 | The original case is made of 2 pieces 87° sewer pipes and that's a cheap and sturdy solution but I wanted something that looked a bit better on my wall so I designed this stevensson screen sensor holder. It fits the sds011 sensor and a DHT22/BME280 besides the mandatory nodeMCU/WemosD1 34 | 35 | # Stevensson what? 36 | A Stevenson screen or instrument shelter is a shelter or an enclosure to shield meteorological instruments against precipitation and direct heat radiation from outside sources, while still allowing air to circulate freely around them. You have probably seen some around in the world without thinking about it but it was first designed at the end of 1880! 37 | 38 | # Parts 39 | 40 | It's enough with 2 bolts to keep it together but if you want to be on the really super safe side it's designed to use 4 bolts. 41 | I recommend that you get stainless bolts and nuts since it'll be placed outside. 42 | ## Printed parts 43 | - 6x middle part 44 | - 1x wall bottom part 45 | - 1x top part 46 | - 1x sds011 holder 47 | 48 | ## Bought parts 49 | - 2-4x M8x100mm bolts 50 | - 2-4x M8 nuts 51 | - 2x wood screws 52 | 53 | # Print Settings 54 | 55 | Printer: RepRapPro Mono Mendel 56 | Rafts: No 57 | Supports: No 58 | Resolution: 0.2 59 | 60 | Notes: 61 | I used a rather high percentage (60%) for the bottom part since it needs to carry the rest of the parts and keeping it stable. 62 | The other parts are just printed with 25% infill since that's as low as I usually go. 63 | 64 | Don't use any support, if you turn all the parts in the right direction it won't be needed. 65 | 66 | # Post-Printing 67 | 68 | ## Step 1: Clean and Count 69 | 70 | Clean all parts from any stringing and make sure you have printed the right number of all the parts. 71 | 72 | ## Step 2: Build the sensor 73 | 74 | Ah yeah, you need a sensor to so head over to [luftdata.se](http://luftdata.se/bygg/) for the Swedish instructions or [luftdaten.info](https://luftdaten.info/en/construction-manual/) for the English instructions. 75 | They also have instructions in a couple of other languages on their site. 76 | 77 | ## Step 3: Attach sensors to the sds011 holder 78 | 79 | Use cable ties to attach the sds011, DHT22/BME280 and NodeMCU/Wemos to the inside of the mesh part. Try to get the ties situated in 4 different corners for making the insertion easier. 80 | 81 | ## Step 4: Fit the nuts to the top part 82 | 83 | My suggstion is to heat up the nuts some and melt them down into the correct places in the top part making sure to get them as straight as possible. 84 | 85 | ## Step 5: Attach the bottom part to a wall 86 | 87 | Use 2 wood screws (max 3,5mm diameter) to fasten the bottom part to a wall, remember that you need to have access to a USB cable to power the unit. 88 | 89 | ## Step 6: Stack the parts 90 | 91 | This part can be a bit tricky so you might want to get help from someone to hand you the pieces. 92 | Start with one bolt from the bottom and while holding it with one hand thread the other _6 middle parts_ onto it. After that insert the mesh holder for the sensor and finally put on the top part and attach the bolt to the nut. 93 | Before you tighten it up to much insert the other bolt(s) and make sure that you manage to line up the holes correctly. -------------------------------------------------------------------------------- /3DDruck/Luftdaten_Stevensson_screen/attribution_card.html: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 |
16 |
17 | 18 |
19 |

Luftdaten Stevensson screen by Naesstrom

20 |

Published on March 10, 2018

21 |

www.thingiverse.com/thing:2821592

22 |

23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | Creative Commons - Attribution

32 |
33 | 34 | 39 | -------------------------------------------------------------------------------- /3DDruck/Luftdaten_Stevensson_screen/files/middle_part_x6.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/Luftdaten_Stevensson_screen/files/middle_part_x6.STL -------------------------------------------------------------------------------- /3DDruck/Luftdaten_Stevensson_screen/files/sds011_holder_x1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/Luftdaten_Stevensson_screen/files/sds011_holder_x1.STL -------------------------------------------------------------------------------- /3DDruck/Luftdaten_Stevensson_screen/files/top_part_x1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/Luftdaten_Stevensson_screen/files/top_part_x1.STL -------------------------------------------------------------------------------- /3DDruck/Luftdaten_Stevensson_screen/files/wall_bottom_part_x1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/Luftdaten_Stevensson_screen/files/wall_bottom_part_x1.STL -------------------------------------------------------------------------------- /3DDruck/Luftdaten_Stevensson_screen/images/160ce06f31e4f0b9b2863523b1d578d7_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/Luftdaten_Stevensson_screen/images/160ce06f31e4f0b9b2863523b1d578d7_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/Luftdaten_Stevensson_screen/images/44aee935f5d444104dc200fb56da6abe_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/Luftdaten_Stevensson_screen/images/44aee935f5d444104dc200fb56da6abe_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/Luftdaten_Stevensson_screen/images/4de7b6a64d3845ae190a4616e7cf8708_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/Luftdaten_Stevensson_screen/images/4de7b6a64d3845ae190a4616e7cf8708_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/Luftdaten_Stevensson_screen/images/da4376fd09404e2d7904c5d9ae312a6a_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/Luftdaten_Stevensson_screen/images/da4376fd09404e2d7904c5d9ae312a6a_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/Luftdaten_Stevensson_screen/images/de5c749b48ccad6f2da1c18631324c17_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/Luftdaten_Stevensson_screen/images/de5c749b48ccad6f2da1c18631324c17_preview_featured.jpg -------------------------------------------------------------------------------- /3DDruck/Luftdaten_Stevensson_screen/images/e4547351a65a82ecb83e4decc64e33e9_preview_featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/3DDruck/Luftdaten_Stevensson_screen/images/e4547351a65a82ecb83e4decc64e33e9_preview_featured.jpg -------------------------------------------------------------------------------- /AS3935_Calibration/AS3935_Calibration.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #define IRQpin 3 3 | #define CSpin 7 4 | 5 | #define AS3935_AFE_GB 0x00, 0x3E 6 | #define AS3935_PWD 0x00, 0x01 7 | #define AS3935_NF_LEV 0x01, 0x70 8 | #define AS3935_WDTH 0x01, 0x0F 9 | #define AS3935_CL_STAT 0x02, 0x40 10 | #define AS3935_MIN_NUM_LIGH 0x02, 0x30 11 | #define AS3935_SREJ 0x02, 0x0F 12 | #define AS3935_LCO_FDIV 0x03, 0xC0 13 | #define AS3935_MASK_DIST 0x03, 0x20 14 | #define AS3935_INT 0x03, 0x0F 15 | #define AS3935_DISTANCE 0x07, 0x3F 16 | #define AS3935_DISP_LCO 0x08, 0x80 17 | #define AS3935_DISP_SRCO 0x08, 0x40 18 | #define AS3935_DISP_TRCO 0x08, 0x20 19 | #define AS3935_TUN_CAP 0x08, 0x0F 20 | #define AS3935_ENERGY_1 0x04, 0xFF 21 | #define AS3935_ENERGY_2 0x05, 0xFF 22 | #define AS3935_ENERGY_3 0x06, 0x1F 23 | 24 | // other constants 25 | #define AS3935_AFE_INDOOR 0x12 26 | #define AS3935_AFE_OUTDOOR 0x0E 27 | 28 | byte SPITransfer2(byte high, byte low) 29 | { 30 | digitalWrite(CSpin, LOW); 31 | SPI.transfer(high); 32 | byte regval = SPI.transfer(low); 33 | digitalWrite(CSpin, HIGH); 34 | return regval; 35 | } 36 | 37 | byte _rawRegisterRead(byte reg) 38 | { 39 | return SPITransfer2((reg & 0x3F) | 0x40, 0); 40 | } 41 | 42 | byte _ffsz(byte mask) 43 | { 44 | byte i = 0; 45 | if (mask) 46 | for (i = 1; ~mask & 1; i++) 47 | mask >>= 1; 48 | return i; 49 | } 50 | 51 | void registerWrite(byte reg, byte mask, byte data) 52 | { 53 | byte regval = _rawRegisterRead(reg); 54 | regval &= ~(mask); 55 | if (mask) 56 | regval |= (data << (_ffsz(mask) - 1)); 57 | else 58 | regval |= data; 59 | SPITransfer2(reg & 0x3F, regval); 60 | } 61 | 62 | byte registerRead(byte reg, byte mask) 63 | { 64 | byte regval = _rawRegisterRead(reg); 65 | regval = regval & mask; 66 | if (mask) 67 | regval >>= (_ffsz(mask) - 1); 68 | return regval; 69 | } 70 | 71 | void powerUp() 72 | { 73 | registerWrite(AS3935_PWD, 0); 74 | SPITransfer2(0x3D, 0x96); 75 | delay(3); 76 | 77 | // Modify REG0x08[5] = 1 78 | registerWrite(AS3935_DISP_TRCO, 1); 79 | delay(2); 80 | // Modify REG0x08[5] = 0 81 | registerWrite(AS3935_DISP_TRCO, 0); 82 | } 83 | 84 | void Areset() 85 | { 86 | SPITransfer2(0x3C, 0x96); 87 | delay(2); 88 | powerUp(); 89 | delay(2); 90 | } 91 | 92 | int tuneAntenna(byte tuneCapacitor) 93 | { 94 | unsigned long setUpTime; 95 | int currentcount = 0; 96 | int currIrq, prevIrq; 97 | 98 | registerWrite(AS3935_LCO_FDIV, 0); 99 | registerWrite(AS3935_DISP_LCO, 1); 100 | 101 | registerWrite(AS3935_TUN_CAP, tuneCapacitor); 102 | 103 | 104 | delay(2); 105 | prevIrq = digitalRead(IRQpin); 106 | setUpTime = millis() + 100; 107 | while ((long)(millis() - setUpTime) < 0) 108 | { 109 | currIrq = digitalRead(IRQpin); 110 | 111 | if (currIrq > prevIrq) 112 | { 113 | currentcount++; 114 | } 115 | prevIrq = currIrq; 116 | } 117 | 118 | registerWrite(AS3935_TUN_CAP, tuneCapacitor); 119 | delay(2); 120 | registerWrite(AS3935_DISP_LCO, 0); 121 | powerUp(); 122 | 123 | return currentcount; 124 | } 125 | void setup() { 126 | digitalWrite(CSpin, HIGH); 127 | pinMode(CSpin, OUTPUT); 128 | pinMode(IRQpin, INPUT); 129 | Serial.begin(57600); 130 | SPI.begin(); 131 | SPI.setDataMode(SPI_MODE1); 132 | SPI.setClockDivider(SPI_CLOCK_DIV2); 133 | SPI.setBitOrder(MSBFIRST); 134 | Serial.println("GO"); 135 | Areset(); 136 | 137 | delay(50); 138 | Serial.println(); 139 | for (byte i = 0; i <= 0x0F; i++) { 140 | int frequency = tuneAntenna(i); 141 | Serial.print("tune antenna to capacitor "); 142 | Serial.print(i); 143 | Serial.print("\t gives frequency: "); 144 | Serial.print(frequency); 145 | Serial.print(" = "); 146 | long fullFreq = (long) frequency * 160; // multiply with clock-divider, and 10 (because measurement is for 100ms) 147 | Serial.print(fullFreq, DEC); 148 | Serial.println(" Hz"); 149 | delay(100); 150 | } 151 | 152 | } 153 | 154 | void loop() { } 155 | -------------------------------------------------------------------------------- /HB-UNI-Sen-WEA.ino: -------------------------------------------------------------------------------- 1 | //- ----------------------------------------------------------------------------------------------------------------------- 2 | // AskSin++ 3 | // 2016-10-31 papa Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ 4 | // some parts (BME280 measurement) from HB-UNI-Sensor1 5 | // 2018-05-11 Tom Major (Creative Commons) 6 | // 2018-05-21 jp112sdl (Creative Commons) 7 | //- ----------------------------------------------------------------------------------------------------------------------- 8 | // #define NDEBUG // disable all serial debuf messages 9 | // #define NSENSORS // if defined, only fake values are used 10 | #define SENSOR_ONLY 11 | 12 | #define EI_NOTEXTERNAL 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include "Sensors/Sens_Bme280.h" 22 | #include "Sensors/Sens_As3935.h" 23 | #include "Sensors/Sens_As5600.h" 24 | #include "Sensors/VentusW132.h" 25 | //#include "Sensors/PCF8574_WindDir.h" 26 | 27 | #define CONFIG_BUTTON_PIN 8 // Anlerntaster-Pin 28 | 29 | ////////// REGENDETEKTOR 30 | //bei Verwendung der Regensensorplatine von stall.biz (https://www.stall.biz/produkt/regenmelder-sensorplatine) 31 | #define RAINDETECTOR_STALLBIZ_SENS_PIN A3 // Pin, an dem der Kondensator angeschlossen ist (hier wird der analoge Wert für die Regenerkennung ermittelt) 32 | #define RAINDETECTOR_STALLBIZ_CRG_PIN 4 // Pin, an dem der Widerstand für die Kondensatoraufladung angeschlossen is 33 | #define RAINDETECTOR_STALLBIZ_HEAT_PIN 9 // Pin, an dem der Transistor für die Heizung angeschlossen ist 34 | #define RAINDETECTOR_STALLBIZ_HEAT_DEWFALL_T 20 // Temperaturschwelle bei aktiviertem "automatisch Heizen bei Erreichen des Taupunkts"; default = 20 (heizen bei +/- 2,0°C um den Taupunkt) 35 | 36 | //bei Verwendung eines Regensensors mit H/L-Pegel Ausgang 37 | #define RAINDETECTOR_PIN 9 // Pin, an dem der Regendetektor angeschlossen ist 38 | #define RAINDETECTOR_PIN_LEVEL_ON_RAIN LOW // Pegel, wenn Regen erkannt wird 39 | 40 | #define RAINDETECTOR_CHECK_INTERVAL 5 // alle x Sekunden auf Regen prüfen 41 | ///////////////////////////////////////////////////////////////////// 42 | 43 | #define WINDSPEEDCOUNTER_PIN 5 // Anemometer 44 | #define RAINQUANTITYCOUNTER_PIN 6 // Regenmengenmesser 45 | 46 | 47 | #define AS3935_ENVIRONMENT ::Sens_As3935<>::AS3935_ENVIRONMENT_OUTDOOR 48 | #define AS3935_IRQ_PIN 3 // IRQ Pin des Blitzdetektors 49 | #define AS3935_CS_PIN_OR_ADDR 7 // SPI: CS Pin / I2C: Address (default: 0x03) 50 | 51 | #define WINDDIRECTION_PIN A2 // Pin, an dem der Windrichtungsanzeiger (RESISTORS oder PULSE) angeschlossen ist 52 | #define WINDDIRECTION_USE_RESISTORS 53 | //#define WINDDIRECTION_USE_PULSE 54 | 55 | //#define WINDDIRECTION_USE_AS5600 56 | //#define WINDDIRECTION_USE_PCF8574 57 | 58 | //#define WINDDIRECTION_USE_VENTUSW132 59 | //#define VENTUSW132_PIN_N A0 // Pins für den Anschluss der 60 | //#define VENTUSW132_PIN_O A1 // 4 Photodioden 61 | //#define VENTUSW132_PIN_S A2 // des Ventus W132 62 | //#define VENTUSW132_PIN_W A6 // Ersatz-Windmessers 63 | 64 | // N O S W 65 | //entspricht Windrichtung in ° 0 , 22.5 , 45 , 67.5 , 90 , 112.5 , 135 , 157.5 , 180 , 202.5 , 225 , 247.5 , 270 , 292.5 , 315 , 337.5 66 | #ifdef WINDDIRECTION_USE_PULSE 67 | const uint16_t WINDDIRS[] = { 70 , 78 , 86 , 94 , 102, 108 , 116 , 0 , 8 , 16 , 24 , 32 , 40 , 48 , 56 , 62 }; 68 | #endif 69 | #ifdef WINDDIRECTION_USE_RESISTORS 70 | const uint16_t WINDDIRS[] = { 58 , 74 , 52 , 115 , 97 , 328 , 302 , 790 , 559 , 663 , 187 , 205 , 163 , 420 , 129 , 153 }; 71 | #endif 72 | #if defined(WINDDIRECTION_USE_VENTUSW132) || defined(WINDDIRECTION_USE_PCF8574) 73 | //direction index 0 1 2 3 4 5 6 7 74 | const uint16_t WINDDIRS[] = { 0, 45, 90, 135, 180, 225, 270, 315 }; 75 | #endif 76 | #ifdef WINDDIRECTION_USE_AS5600 77 | const uint16_t WINDDIRS[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 78 | #endif 79 | 80 | #define WINDSPEED_MEASUREINTERVAL_SECONDS 5 // Messintervall (Sekunden) für Windgeschwindigkeit / Böen 81 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 82 | 83 | 84 | //some static definitions 85 | #define WINDSPEED_MAX 0x3FFF 86 | #define GUSTSPEED_MAX 0x7FFF 87 | #define RAINCOUNTER_MAX 0x7FFF 88 | #define STORM_COND_VALUE_LO 100 89 | #define STORM_COND_VALUE_HI 200 90 | #define PEERS_PER_CHANNEL 4 91 | 92 | using namespace as; 93 | 94 | volatile uint32_t _rainquantity_isr_counter = 0; 95 | volatile uint16_t _wind_isr_counter = 0; 96 | 97 | void rainquantitycounterISR() { 98 | _rainquantity_isr_counter++; 99 | } 100 | void windspeedcounterISR() { 101 | _wind_isr_counter++; 102 | } 103 | 104 | enum eventMessageSources {EVENT_SRC_RAINING, EVENT_SRC_HEATING, EVENT_SRC_GUST}; 105 | 106 | const struct DeviceInfo PROGMEM devinfo = { 107 | {0xF1, 0xD0, 0x02}, // Device ID 108 | "JPWEA00002", // Device Serial 109 | {0xF1, 0xD0}, // Device Model 110 | 0x14, // Firmware Version 111 | as::DeviceType::THSensor, // Device Type 112 | {0x01, 0x01} // Info Bytes 113 | }; 114 | 115 | // Configure the used hardware 116 | typedef AskSin, 2>> Hal; 117 | Hal hal; 118 | 119 | class WeatherEventMsg : public Message { 120 | public: 121 | void init(uint8_t msgcnt, int16_t temp, uint16_t airPressure, uint8_t humidity, uint32_t brightness, bool israining, bool isheating, uint16_t raincounter, uint16_t windspeed, uint8_t winddir, uint8_t winddirrange, uint16_t gustspeed, uint8_t uvindex, uint8_t lightningcounter, uint8_t lightningdistance) { 122 | Message::init(0x1a, msgcnt, 0x70, BIDI | RPTEN, (temp >> 8) & 0x7f, temp & 0xff); 123 | pload[0] = (airPressure >> 8) & 0xff; 124 | pload[1] = airPressure & 0xff; 125 | pload[2] = humidity; 126 | pload[3] = (brightness >> 16) & 0xff; 127 | pload[4] = (brightness >> 8) & 0xff; 128 | pload[5] = brightness & 0xff; 129 | pload[6] = ((raincounter >> 8) & 0xff) | (israining << 7); 130 | pload[7] = raincounter & 0xff; 131 | pload[8] = ((windspeed >> 8) & 0xff) | (winddirrange << 6); 132 | pload[9] = windspeed & 0xff; 133 | pload[10] = winddir; 134 | pload[11] = ((gustspeed >> 8) & 0xff) | (isheating << 7); 135 | pload[12] = gustspeed & 0xff; 136 | pload[13] = (uvindex & 0xff) | (lightningdistance << 4); 137 | pload[14] = lightningcounter & 0xff; 138 | } 139 | }; 140 | 141 | class ExtraEventMsg : public Message { 142 | public: 143 | void init(uint8_t msgcnt, bool israining, bool isheating, uint16_t gustspeed) { 144 | Message::init(0x0d, msgcnt, 0x53, BIDI | RPTEN, 0x41, (israining & 0xff) | (isheating << 1)); 145 | pload[0] = (gustspeed >> 8) & 0xff; 146 | pload[1] = gustspeed & 0xff; 147 | } 148 | }; 149 | 150 | DEFREGISTER(Reg0, MASTERID_REGS, DREG_TRANSMITTRYMAX, 0x20, 0x21, 0x22, 0x23) 151 | class SensorList0 : public RegList0 { 152 | public: 153 | SensorList0(uint16_t addr) : RegList0(addr) {} 154 | 155 | bool updIntervall (uint16_t value) const { 156 | return this->writeRegister(0x20, (value >> 8) & 0xff) && this->writeRegister(0x21, value & 0xff); 157 | } 158 | uint16_t updIntervall () const { 159 | return (this->readRegister(0x20, 0) << 8) + this->readRegister(0x21, 0); 160 | } 161 | 162 | bool height (uint16_t value) const { 163 | return this->writeRegister(0x22, (value >> 8) & 0xff) && this->writeRegister(0x23, value & 0xff); 164 | } 165 | uint16_t height () const { 166 | return (this->readRegister(0x22, 0) << 8) + this->readRegister(0x23, 0); 167 | } 168 | 169 | void defaults () { 170 | clear(); 171 | updIntervall(60); 172 | height(0); 173 | transmitDevTryMax(6); 174 | } 175 | }; 176 | 177 | DEFREGISTER(Reg1, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16) 178 | class SensorList1 : public RegList1 { 179 | public: 180 | SensorList1 (uint16_t addr) : RegList1(addr) {} 181 | bool AnemometerRadius (uint8_t value) const { 182 | return this->writeRegister(0x01, value & 0xff); 183 | } 184 | uint8_t AnemometerRadius () const { 185 | return this->readRegister(0x01, 0); 186 | } 187 | 188 | bool AnemometerCalibrationFactor (uint16_t value) const { 189 | return this->writeRegister(0x02, (value >> 8) & 0xff) && this->writeRegister(0x03, value & 0xff); 190 | } 191 | uint16_t AnemometerCalibrationFactor () const { 192 | return (this->readRegister(0x02, 0) << 8) + this->readRegister(0x03, 0); 193 | } 194 | 195 | bool LightningDetectorCapacitor (uint8_t value) const { 196 | return this->writeRegister(0x04, value & 0xff); 197 | } 198 | uint8_t LightningDetectorCapacitor () const { 199 | return this->readRegister(0x04, 0); 200 | } 201 | 202 | bool LightningDetectorMinStrikes (uint8_t value) const { 203 | return this->writeRegister(0x12, value & 0xff); 204 | } 205 | uint8_t LightningDetectorMinStrikes () const { 206 | return this->readRegister(0x12, 0); 207 | } 208 | 209 | bool LightningDetectorWatchdogThreshold (uint8_t value) const { 210 | return this->writeRegister(0x13, value & 0xff); 211 | } 212 | uint8_t LightningDetectorWatchdogThreshold () const { 213 | return this->readRegister(0x13, 0); 214 | } 215 | 216 | bool LightningDetectorNoiseFloorLevel (uint8_t value) const { 217 | return this->writeRegister(0x14, value & 0xff); 218 | } 219 | uint8_t LightningDetectorNoiseFloorLevel () const { 220 | return this->readRegister(0x14, 0); 221 | } 222 | 223 | bool LightningDetectorSpikeRejection (uint8_t value) const { 224 | return this->writeRegister(0x15, value & 0xff); 225 | } 226 | uint8_t LightningDetectorSpikeRejection () const { 227 | return this->readRegister(0x15, 0); 228 | } 229 | 230 | bool LightningDetectorDisturberDetection () const { 231 | return this->readBit(0x05, 0, true); 232 | } 233 | bool LightningDetectorDisturberDetection (bool v) const { 234 | return this->writeBit(0x05, 0, v); 235 | } 236 | 237 | bool ExtraMessageOnGustThreshold (uint8_t value) const { 238 | return this->writeRegister(0x06, value & 0xff); 239 | } 240 | uint8_t ExtraMessageOnGustThreshold () const { 241 | return this->readRegister(0x06, 0); 242 | } 243 | 244 | bool StormUpperThreshold (uint8_t value) const { 245 | return this->writeRegister(0x07, value & 0xff); 246 | } 247 | uint8_t StormUpperThreshold () const { 248 | return this->readRegister(0x07, 0); 249 | } 250 | 251 | bool StormLowerThreshold (uint8_t value) const { 252 | return this->writeRegister(0x08, value & 0xff); 253 | } 254 | uint8_t StormLowerThreshold () const { 255 | return this->readRegister(0x08, 0); 256 | } 257 | 258 | bool RaindetectorStallBizHiThresholdRain (uint16_t value) const { 259 | return this->writeRegister(0x09, (value >> 8) & 0xff) && this->writeRegister(0x0a, value & 0xff); 260 | } 261 | uint16_t RaindetectorStallBizHiThresholdRain () const { 262 | return (this->readRegister(0x09, 0) << 8) + this->readRegister(0x0a, 0); 263 | } 264 | bool RaindetectorStallBizLoThresholdRain (uint16_t value) const { 265 | return this->writeRegister(0x0b, (value >> 8) & 0xff) && this->writeRegister(0x0c, value & 0xff); 266 | } 267 | uint16_t RaindetectorStallBizLoThresholdRain () const { 268 | return (this->readRegister(0x0b, 0) << 8) + this->readRegister(0x0c, 0); 269 | } 270 | bool RaindetectorStallBizHiThresholdHeater (uint16_t value) const { 271 | return this->writeRegister(0x0d, (value >> 8) & 0xff) && this->writeRegister(0x0e, value & 0xff); 272 | } 273 | uint16_t RaindetectorStallBizHiThresholdHeater () const { 274 | return (this->readRegister(0x0d, 0) << 8) + this->readRegister(0x0e, 0); 275 | } 276 | bool RaindetectorStallBizLoThresholdHeater (uint16_t value) const { 277 | return this->writeRegister(0x0f, (value >> 8) & 0xff) && this->writeRegister(0x10, value & 0xff); 278 | } 279 | uint16_t RaindetectorStallBizLoThresholdHeater () const { 280 | return (this->readRegister(0x0f, 0) << 8) + this->readRegister(0x10, 0); 281 | } 282 | 283 | bool RaindetectorSensorType (uint8_t value) const { 284 | return this->writeRegister(0x11, value & 0xff); 285 | } 286 | uint8_t RaindetectorSensorType () const { 287 | return this->readRegister(0x11, 0); 288 | } 289 | 290 | bool RaindetectorStallBizHeatOnDewfall () const { 291 | return this->readBit(0x16, 0, true); 292 | } 293 | bool RaindetectorStallBizHeatOnDewfall (bool v) const { 294 | return this->writeBit(0x16, 0, v); 295 | } 296 | 297 | void defaults () { 298 | clear(); 299 | AnemometerRadius(65); 300 | AnemometerCalibrationFactor(10); 301 | LightningDetectorCapacitor(80); 302 | LightningDetectorDisturberDetection(true); 303 | ExtraMessageOnGustThreshold(0); 304 | StormUpperThreshold(0); 305 | StormLowerThreshold(0); 306 | RaindetectorSensorType(0); 307 | RaindetectorStallBizHiThresholdRain(750); 308 | RaindetectorStallBizLoThresholdRain(500); 309 | RaindetectorStallBizHiThresholdHeater(500); 310 | RaindetectorStallBizLoThresholdHeater(400); 311 | RaindetectorStallBizHeatOnDewfall(true); 312 | LightningDetectorMinStrikes(0); 313 | LightningDetectorSpikeRejection(2); 314 | LightningDetectorWatchdogThreshold(2); 315 | LightningDetectorNoiseFloorLevel(2); 316 | } 317 | }; 318 | 319 | class WeatherChannel : public Channel, public Alarm { 320 | int16_t temperature; 321 | uint16_t airPressure; 322 | uint8_t humidity; 323 | uint32_t brightness; 324 | bool israining; 325 | bool isheating; 326 | uint16_t raincounter; 327 | uint16_t windspeed; 328 | uint16_t gustspeed; 329 | uint16_t uvindex; 330 | uint8_t lightningcounter; 331 | uint8_t lightningdistance; 332 | 333 | uint8_t winddir; 334 | uint8_t winddirrange; 335 | 336 | uint16_t stormUpperThreshold; 337 | uint16_t stormLowerThreshold; 338 | 339 | bool initComplete; 340 | bool initLightningDetectorDone; 341 | uint8_t short_interval_measure_count; 342 | uint8_t israining_alarm_count; 343 | 344 | Sens_Bme280 bme280; 345 | Veml6070 veml6070; 346 | MAX44009<> max44009; 347 | #ifdef WINDDIRECTION_USE_AS5600 348 | Sens_As5600 as5600; 349 | #endif 350 | #ifdef WINDDIRECTION_USE_VENTUSW132 351 | VentusW132 ventus; 352 | #endif 353 | #ifdef WINDDIRECTION_USE_PCF8574 354 | PCF8574_WindDir<0x38> pcf; 355 | #endif 356 | 357 | public: 358 | #ifdef __SENSORS_AS3935_h__ 359 | Sens_As3935 as3935; 360 | #endif 361 | public: 362 | WeatherChannel () : Channel(), Alarm(seconds2ticks(60)), temperature(0), airPressure(0), humidity(0), brightness(0), israining(false), isheating(false), raincounter(0), windspeed(0), gustspeed(0), uvindex(0), lightningcounter(0), lightningdistance(0), winddir(0), winddirrange(0), stormUpperThreshold(0), stormLowerThreshold(0), initComplete(false), initLightningDetectorDone(false), short_interval_measure_count(0), israining_alarm_count(0), wind_and_uv_measure(*this), lightning_and_raining_check(*this) {} 363 | virtual ~WeatherChannel () {} 364 | 365 | class WindSpeedAndUVMeasureAlarm : public Alarm { 366 | WeatherChannel& chan; 367 | public: 368 | WindSpeedAndUVMeasureAlarm (WeatherChannel& c) : Alarm (seconds2ticks(WINDSPEED_MEASUREINTERVAL_SECONDS)), chan(c) {} 369 | virtual ~WindSpeedAndUVMeasureAlarm () {} 370 | 371 | void trigger (__attribute__ ((unused)) AlarmClock& clock) { 372 | chan.measure_windspeed(); 373 | chan.measure_uvindex(); 374 | tick = (seconds2ticks(WINDSPEED_MEASUREINTERVAL_SECONDS)); 375 | clock.add(*this); 376 | chan.short_interval_measure_count++; 377 | } 378 | } wind_and_uv_measure; 379 | 380 | class LightningAndRainingAlarm : public Alarm { 381 | WeatherChannel& chan; 382 | public: 383 | LightningAndRainingAlarm (WeatherChannel& c) : Alarm (seconds2ticks(1)), chan(c) {} 384 | virtual ~LightningAndRainingAlarm () {} 385 | 386 | void trigger (__attribute__ ((unused)) AlarmClock& clock) { 387 | chan.measure_lightning(); 388 | chan.measure_israining(); 389 | tick = (seconds2ticks(1)); 390 | clock.add(*this); 391 | } 392 | } lightning_and_raining_check; 393 | 394 | 395 | virtual void trigger (__attribute__ ((unused)) AlarmClock& clock) { 396 | measure_winddirection(); 397 | measure_thpb(); 398 | measure_rainquantity(); 399 | 400 | if (initComplete) { 401 | windspeed = windspeed / short_interval_measure_count; 402 | if (windspeed > WINDSPEED_MAX) windspeed = WINDSPEED_MAX; 403 | uvindex = uvindex / short_interval_measure_count; 404 | } 405 | 406 | //DPRINT(F("GUSTSPEED : ")); DDECLN(gustspeed); 407 | //DPRINT(F("WINDSPEED : ")); DDECLN(windspeed); 408 | //DPRINT(F("UV Index : ")); DDECLN(uvindex); 409 | WeatherEventMsg& msg = (WeatherEventMsg&)device().message(); 410 | uint8_t msgcnt = device().nextcount(); 411 | msg.init(msgcnt, temperature, airPressure, humidity, brightness, israining, isheating, raincounter, windspeed, winddir, winddirrange, gustspeed, uvindex, lightningcounter, lightningdistance); 412 | if (msgcnt % 20 == 1) { 413 | device().sendMasterEvent(msg); 414 | } else { 415 | device().broadcastEvent(msg); 416 | } 417 | uint16_t updCycle = this->device().getList0().updIntervall(); 418 | tick = seconds2ticks(updCycle); 419 | 420 | initComplete = true; 421 | windspeed = 0; 422 | gustspeed = 0; 423 | uvindex = 0; 424 | short_interval_measure_count = 0; 425 | sysclock.add(*this); 426 | } 427 | 428 | void sendExtraMessage (uint8_t t) { 429 | DPRINT(F("SENDING EXTRA MESSAGE ")); DDECLN(t); 430 | ExtraEventMsg& extramsg = (ExtraEventMsg&)device().message(); 431 | extramsg.init(device().nextcount(), israining, isheating, gustspeed); 432 | device().sendMasterEvent(extramsg); 433 | } 434 | 435 | void measure_windspeed() { 436 | #ifdef NSENSORS 437 | _wind_isr_counter = random(20); 438 | #endif 439 | //V = 2 * R * Pi * N 440 | // int kmph = 3.141593 * 2 * ((float)anemometerRadius / 100) * ((float)_wind_isr_counter / (float)WINDSPEED_MEASUREINTERVAL_SECONDS) * 3.6 * ((float)anemometerCalibrationFactor / 10); 441 | uint16_t kmph = ((226L * this->getList1().AnemometerRadius() * this->getList1().AnemometerCalibrationFactor() * _wind_isr_counter) / WINDSPEED_MEASUREINTERVAL_SECONDS) / 10000; 442 | if (kmph > gustspeed) { 443 | gustspeed = (kmph > GUSTSPEED_MAX) ? GUSTSPEED_MAX : kmph; 444 | } 445 | 446 | if (this->getList1().ExtraMessageOnGustThreshold() > 0 && kmph > (this->getList1().ExtraMessageOnGustThreshold() * 10)) { 447 | sendExtraMessage(EVENT_SRC_GUST); 448 | } 449 | 450 | //DPRINT(F("WIND kmph : ")); DDECLN(kmph); 451 | //DPRINT(F("UPPER THRESH : ")); DDECLN(stormUpperThreshold); 452 | //DPRINT(F("LOWER THRESH : ")); DDECLN(stormLowerThreshold); 453 | 454 | static uint8_t STORM_COND_VALUE_Last = STORM_COND_VALUE_LO; 455 | static uint8_t STORM_COND_VALUE = STORM_COND_VALUE_LO; 456 | 457 | if (stormUpperThreshold > 0) { 458 | if (kmph >= stormUpperThreshold || kmph <= stormLowerThreshold) { 459 | static uint8_t evcnt = 0; 460 | 461 | if (kmph >= stormUpperThreshold) STORM_COND_VALUE = STORM_COND_VALUE_HI; 462 | if (kmph <= stormLowerThreshold) STORM_COND_VALUE = STORM_COND_VALUE_LO; 463 | 464 | if (STORM_COND_VALUE != STORM_COND_VALUE_Last) { 465 | SensorEventMsg& rmsg = (SensorEventMsg&)device().message(); 466 | //DPRINT(F("PEER THRESHOLD DETECTED ")); DDECLN(STORM_COND_VALUE); 467 | rmsg.init(device().nextcount(), number(), evcnt++, STORM_COND_VALUE, false , false); 468 | device().sendPeerEvent(rmsg, *this); 469 | } 470 | STORM_COND_VALUE_Last = STORM_COND_VALUE; 471 | } 472 | } 473 | 474 | windspeed += kmph; 475 | _wind_isr_counter = 0; 476 | } 477 | 478 | void measure_israining() { 479 | static bool wasraining = false; 480 | 481 | if (initComplete) { 482 | if (israining_alarm_count >= RAINDETECTOR_CHECK_INTERVAL) { 483 | switch (this->getList1().RaindetectorSensorType()) { 484 | case 0: 485 | israining = (digitalRead(RAINDETECTOR_PIN) == RAINDETECTOR_PIN_LEVEL_ON_RAIN); 486 | break; 487 | case 1: 488 | digitalWrite(RAINDETECTOR_STALLBIZ_CRG_PIN, HIGH); 489 | _delay_ms(2); 490 | digitalWrite(RAINDETECTOR_STALLBIZ_CRG_PIN, LOW); 491 | uint16_t rdVal = analogRead(RAINDETECTOR_STALLBIZ_SENS_PIN); 492 | //DPRINT(F("RD aVal : ")); DDECLN(rdVal); 493 | 494 | if (rdVal > this->getList1().RaindetectorStallBizHiThresholdRain()) { 495 | israining = true; 496 | } 497 | if (rdVal < this->getList1().RaindetectorStallBizLoThresholdRain()) { 498 | israining = false; 499 | } 500 | 501 | static bool mustheat = false; 502 | if (rdVal > this->getList1().RaindetectorStallBizHiThresholdHeater()) { 503 | mustheat = true; 504 | } 505 | if (rdVal < (this->getList1().RaindetectorStallBizLoThresholdHeater())) { 506 | mustheat = false; 507 | } 508 | 509 | bool dewfall = false; 510 | if (this->getList1().RaindetectorStallBizHeatOnDewfall() == true) 511 | dewfall = bme280.present() ? (abs(bme280.temperature() - bme280.dewPoint()) < RAINDETECTOR_STALLBIZ_HEAT_DEWFALL_T) : false; 512 | 513 | // Heizung schalten 514 | raindetector_heater(mustheat || dewfall); 515 | } 516 | 517 | //DPRINT(F("RD israining : ")); DDECLN(israining); 518 | 519 | if (wasraining != israining) { 520 | sendExtraMessage(EVENT_SRC_RAINING); 521 | static uint8_t evcnt = 0; 522 | SensorEventMsg& rmsg = (SensorEventMsg&)device().message(); 523 | rmsg.init(device().nextcount(), number(), evcnt++, israining ? 200 : 0, true , false); 524 | device().sendPeerEvent(rmsg, *this); 525 | } 526 | wasraining = israining; 527 | israining_alarm_count = 0; 528 | } 529 | israining_alarm_count++; 530 | } 531 | } 532 | 533 | void raindetector_heater(bool State) { 534 | static bool washeating = false; 535 | static uint8_t pwmval = 0; 536 | isheating = State; 537 | 538 | if (State == true) { 539 | if (pwmval < 255) pwmval = pwmval + 51; 540 | } else { 541 | pwmval = 0; 542 | } 543 | analogWrite(RAINDETECTOR_STALLBIZ_HEAT_PIN, pwmval); 544 | 545 | //DPRINT(F("RD HEAT : ")); DDECLN(State); 546 | //DPRINT(F("RD HEAT PWM : ")); DDECLN(pwmval); 547 | 548 | 549 | if (washeating != State) { 550 | sendExtraMessage(EVENT_SRC_HEATING); 551 | } 552 | washeating = State; 553 | } 554 | 555 | void measure_uvindex() { 556 | #ifdef NSENSORS 557 | uvindex += random(11); 558 | #else 559 | veml6070.measure(); 560 | //DPRINT(F("UV readUV : ")); DDECLN(veml6070.UVValue()); 561 | uvindex += veml6070.UVIndex(); 562 | #endif 563 | } 564 | 565 | void measure_winddirection() { 566 | //Windrichtung Grad/3: 60° = 20; 0° = Norden 567 | winddir = 0; 568 | uint8_t idxwdir = 0; 569 | #ifdef NSENSORS 570 | idxwdir = random(15); 571 | winddir = (idxwdir * 15 + 2 / 2) / 2; 572 | #else 573 | 574 | 575 | #ifdef WINDDIRECTION_USE_AS5600 576 | as5600.measure(); 577 | winddir = as5600.angle() / 3; 578 | idxwdir = winddir * 10 / 75; 579 | DPRINT(F("WINDDIR angle : ")); DDECLN(as5600.angle()); 580 | #endif 581 | 582 | #ifdef WINDDIRECTION_USE_VENTUSW132 583 | //winddir = ventus.winddirValue(); 584 | idxwdir = ventus.winddirValue(true); 585 | winddir = WINDDIRS[idxwdir] / 3; 586 | DPRINT(F("WINDDIR value (=dir / 3) : ")); DDECLN(winddir); 587 | #endif 588 | 589 | #ifdef WINDDIRECTION_USE_PCF8574 590 | idxwdir = pcf.winddirValue(true); 591 | winddir = WINDDIRS[idxwdir] / 3; 592 | DPRINT(F("WINDDIR value (=dir / 3) : ")); DDECLN(winddir); 593 | #endif 594 | 595 | #ifdef WINDDIRECTION_USE_PULSE 596 | uint8_t aVal = 0; 597 | uint8_t WINDDIR_TOLERANCE = 3; 598 | aVal = pulseIn(WINDDIRECTION_PIN, HIGH, 1000); 599 | DPRINT("AVAL = "); DDECLN(aVal); 600 | #endif 601 | 602 | #ifdef WINDDIRECTION_USE_RESISTORS 603 | uint16_t aVal = 0; 604 | for (uint8_t i = 0; i <= 0xf; i++) { 605 | aVal += analogRead(WINDDIRECTION_PIN); 606 | } 607 | aVal = aVal >> 4; 608 | 609 | uint8_t WINDDIR_TOLERANCE = 2; 610 | if ((aVal > 100) && (aVal < 250)) WINDDIR_TOLERANCE = 5; 611 | if (aVal >= 250) WINDDIR_TOLERANCE = 10; 612 | #endif 613 | 614 | #if !defined(WINDDIRECTION_USE_AS5600) && !defined(WINDDIRECTION_USE_VENTUSW132) && !defined(WINDDIRECTION_USE_PCF8574) 615 | for (uint8_t i = 0; i < sizeof(WINDDIRS) / sizeof(uint16_t); i++) { 616 | if (aVal < WINDDIRS[i] + WINDDIR_TOLERANCE && aVal > WINDDIRS[i] - WINDDIR_TOLERANCE) { 617 | idxwdir = i; 618 | winddir = (idxwdir * 15 + 2 / 2) / 2; 619 | break; 620 | } 621 | } 622 | DPRINT(F("WINDDIR aVal : ")); DDEC(aVal); DPRINT(F(" :: tolerance = ")); DDEC(WINDDIR_TOLERANCE); DPRINT(F(" :: i = ")); DDECLN(idxwdir); 623 | #endif 624 | 625 | 626 | #endif 627 | 628 | //Schwankungsbreite 629 | static uint8_t idxoldwdir = 0; 630 | winddirrange = 3; // 0 - 3 (0, 22,5, 45, 67,5°) 631 | int idxdiff = abs(idxwdir - idxoldwdir); 632 | 633 | uint8_t num_winddirs = sizeof(WINDDIRS) / sizeof(uint16_t); 634 | 635 | if (idxdiff <= 3) winddirrange = idxdiff; 636 | if (idxwdir <= 2 && idxoldwdir >= (num_winddirs-3)) winddirrange = num_winddirs - idxdiff; 637 | if (winddirrange > 3) winddirrange = 3; 638 | 639 | idxoldwdir = idxwdir; 640 | 641 | //DPRINT(F("WINDDIR dir/3 : ")); DDECLN(winddir); 642 | //DPRINT(F("WINDDIR range : ")); DDECLN(winddirrange); 643 | } 644 | 645 | void measure_rainquantity() { 646 | #ifdef NSENSORS 647 | _rainquantity_isr_counter++; 648 | #endif 649 | if (!initComplete) { 650 | _rainquantity_isr_counter = 0; 651 | //DPRINTLN(F("RAINCOUNTER : initalize")); 652 | } else { 653 | if (_rainquantity_isr_counter > RAINCOUNTER_MAX) { 654 | _rainquantity_isr_counter = 1; 655 | } 656 | raincounter = _rainquantity_isr_counter; 657 | } 658 | //DPRINT(F("RAINCOUNTER : ")); DDECLN(_rainquantity_isr_counter); 659 | } 660 | 661 | void measure_lightning() { 662 | #if defined(NSENSORS) || !defined(__SENSORS_AS3935_h__) 663 | lightningcounter = 0; 664 | lightningdistance = 0; 665 | #else 666 | if (!initLightningDetectorDone) { 667 | as3935.init(this->getList1().LightningDetectorCapacitor(), 668 | this->getList1().LightningDetectorDisturberDetection(), 669 | AS3935_ENVIRONMENT, 670 | this->getList1().LightningDetectorMinStrikes(), 671 | this->getList1().LightningDetectorWatchdogThreshold(), 672 | this->getList1().LightningDetectorNoiseFloorLevel(), 673 | this->getList1().LightningDetectorSpikeRejection()); 674 | initLightningDetectorDone = true; 675 | } else { 676 | uint8_t lightning_dist_km = 0; 677 | if (as3935.LightningIsrCounter() > 0) { 678 | switch (as3935.GetInterruptSrc()) { 679 | case 0: 680 | DPRINTLN(F("LD IRQ SRC NOT EXPECTED")); 681 | break; 682 | case 1: 683 | lightning_dist_km = as3935.LightningDistKm(); 684 | DPRINT(F("LD LIGHTNING IN ")); DDEC(lightning_dist_km); DPRINTLN(" km"); 685 | lightningcounter++; 686 | // Wenn Zähler überläuft (255 + 1), dann 1 statt 0 687 | if (lightningcounter == 0) lightningcounter = 1; 688 | lightningdistance = (lightning_dist_km + 1) / 3; 689 | break; 690 | case 2: 691 | DPRINTLN(F("LD DIST")); 692 | break; 693 | case 3: 694 | DPRINTLN(F("LD NOISE")); 695 | break; 696 | } 697 | as3935.ResetLightninIsrCounter(); 698 | } 699 | } 700 | #endif 701 | //DPRINT(F("LD CNT : ")); DDECLN(lightningcounter); 702 | //DPRINT(F("LD DIST : ")); DDECLN(lightningdistance); 703 | } 704 | 705 | void measure_thpb() { 706 | uint16_t height = this->device().getList0().height(); 707 | #ifdef NSENSORS 708 | airPressure = 9000 + random(2000); // 1024 hPa +x 709 | humidity = 66 + random(7); // 66% +x 710 | temperature = 150 + random(50); // 15C +x 711 | brightness = 1700000 + random(10000); // 67000 Lux +x 712 | //DPRINT(F(" airPressure : ")); DDECLN(airPressure); 713 | //DPRINT(F(" humidity : ")); DDECLN(humidity); 714 | //DPRINT(F(" temperature : ")); DDECLN(temperature); 715 | //DPRINT(F(" brightness : ")); DDECLN(brightness); 716 | #else 717 | bme280.measure(height); 718 | temperature = bme280.temperature(); 719 | airPressure = bme280.pressureNN(); 720 | humidity = bme280.humidity(); 721 | 722 | max44009.measure(); 723 | brightness = max44009.brightness(); 724 | //DPRINT(F("BRIGHTNESS : ") ); DDECLN(brightness); 725 | #endif 726 | } 727 | 728 | void setup(Device* dev, uint8_t number, uint16_t addr) { 729 | Channel::setup(dev, number, addr); 730 | tick = seconds2ticks(3); // first message in 3 sec. 731 | #ifndef NSENSORS 732 | max44009.init(); 733 | bme280.init(); 734 | veml6070.init(); 735 | #endif 736 | #ifdef WINDDIRECTION_USE_AS5600 737 | as5600.init(); 738 | #endif 739 | #ifdef WINDDIRECTION_USE_VENTUSW132 740 | ventus.init(); 741 | #endif 742 | #ifdef WINDDIRECTION_USE_PCF8574 743 | pcf.init(); 744 | #endif 745 | sysclock.add(*this); 746 | sysclock.add(wind_and_uv_measure); 747 | sysclock.add(lightning_and_raining_check); 748 | } 749 | 750 | void configChanged() { 751 | DPRINTLN("* Config changed : List1"); 752 | //DPRINTLN(F("* ANEMOMETER : ")); 753 | //DPRINT(F("* - RADIUS : ")); DDECLN(this->getList1().AnemometerRadius()); 754 | //DPRINT(F("* - CALIBRATIONFACTOR : ")); DDECLN(this->getList1().AnemometerCalibrationFactor()); 755 | //DPRINT(F("* - GUST MSG THRESHOLD: ")); DDECLN(this->getList1().ExtraMessageOnGustThreshold()); 756 | //DPRINTLN(F("* LIGHTNINGDETECTOR : ")); 757 | //DPRINT(F("* - CAPACITOR : ")); DDECLN(this->getList1().LightningDetectorCapacitor()); 758 | //DPRINT(F("* - DISTURB.DETECTION : ")); DDECLN(this->getList1().LightningDetectorDisturberDetection()); 759 | //DPRINT(F("* - WATCHDOGTHRESHOLD : ")); DDECLN(this->getList1().LightningDetectorWatchdogThreshold()); 760 | //DPRINT(F("* - SPIKREJECTION : ")); DDECLN(this->getList1().LightningDetectorSpikeRejection()); 761 | //DPRINT(F("* - NOISEFLOORLEVEL : ")); DDECLN(this->getList1().LightningDetectorNoiseFloorLevel()); 762 | //DPRINT(F("* - MINSTRIKES : ")); DDECLN(this->getList1().LightningDetectorMinStrikes()); 763 | //DPRINT(F("PEERSETTING UPPER = ")); DDECLN(this->getList1().StormUpperThreshold()); 764 | stormUpperThreshold = this->getList1().StormUpperThreshold() * 10; 765 | //DPRINT(F("PEERSETTING LOWER = ")); DDECLN(this->getList1().StormLowerThreshold()); 766 | stormLowerThreshold = this->getList1().StormLowerThreshold() * 10; 767 | //DPRINT(F("RAINDETECTOR SENSORTYPE = ")); DDECLN(this->getList1().RaindetectorSensorType()); 768 | //DPRINT(F("RaindetectorStallBizHiThresholdRain = ")); DDECLN(this->getList1().RaindetectorStallBizHiThresholdRain()); 769 | //DPRINT(F("RaindetectorStallBizLoThresholdRain = ")); DDECLN(this->getList1().RaindetectorStallBizLoThresholdRain()); 770 | //DPRINT(F("RaindetectorStallBizHiThresholdHeater = ")); DDECLN(this->getList1().RaindetectorStallBizHiThresholdHeater()); 771 | //DPRINT(F("RaindetectorStallBizLoThresholdHeater = ")); DDECLN(this->getList1().RaindetectorStallBizLoThresholdHeater()); 772 | //DPRINT(F("RaindetectorStallBizHeatOnDewfall = ")); DDECLN(this->getList1().RaindetectorStallBizHeatOnDewfall()); 773 | switch (this->getList1().RaindetectorSensorType()) { 774 | case 0: 775 | pinMode(RAINDETECTOR_PIN, INPUT_PULLUP); 776 | break; 777 | case 1: 778 | pinMode(RAINDETECTOR_STALLBIZ_CRG_PIN, OUTPUT); 779 | pinMode(RAINDETECTOR_STALLBIZ_HEAT_PIN, OUTPUT); 780 | pinMode(RAINDETECTOR_STALLBIZ_SENS_PIN, INPUT); 781 | break; 782 | } 783 | 784 | initLightningDetectorDone = false; 785 | } 786 | 787 | uint8_t status () const { 788 | return 0; 789 | } 790 | 791 | uint8_t flags () const { 792 | return 0; 793 | } 794 | }; 795 | 796 | class SensChannelDevice : public MultiChannelDevice { 797 | public: 798 | typedef MultiChannelDevice TSDevice; 799 | SensChannelDevice(const DeviceInfo& info, uint16_t addr) : TSDevice(info, addr) {} 800 | virtual ~SensChannelDevice () {} 801 | 802 | virtual void configChanged () { 803 | TSDevice::configChanged(); 804 | DPRINTLN("* Config Changed : List0"); 805 | DPRINT(F("* SENDEINTERVALL : ")); DDECLN(this->getList0().updIntervall()); 806 | //DPRINT(F("* ALTITUDE : ")); DDECLN(this->getList0().height()); 807 | //DPRINT(F("* TRANSMITTRYMAX : ")); DDECLN(this->getList0().transmitDevTryMax()); 808 | } 809 | }; 810 | 811 | SensChannelDevice sdev(devinfo, 0x20); 812 | ConfigButton cfgBtn(sdev); 813 | 814 | void setup () { 815 | DINIT(57600, ASKSIN_PLUS_PLUS_IDENTIFIER); 816 | sdev.init(hal); 817 | buttonISR(cfgBtn, CONFIG_BUTTON_PIN); 818 | sdev.initDone(); 819 | //sdev.startPairing(); 820 | pinMode(RAINQUANTITYCOUNTER_PIN, INPUT_PULLUP); 821 | pinMode(WINDSPEEDCOUNTER_PIN, INPUT_PULLUP); 822 | pinMode(WINDDIRECTION_PIN, INPUT_PULLUP); 823 | 824 | if ( digitalPinToInterrupt(RAINQUANTITYCOUNTER_PIN) == NOT_AN_INTERRUPT ) enableInterrupt(RAINQUANTITYCOUNTER_PIN, rainquantitycounterISR, RISING); else attachInterrupt(digitalPinToInterrupt(RAINQUANTITYCOUNTER_PIN), rainquantitycounterISR, RISING); 825 | if ( digitalPinToInterrupt(WINDSPEEDCOUNTER_PIN) == NOT_AN_INTERRUPT ) enableInterrupt(WINDSPEEDCOUNTER_PIN, windspeedcounterISR, RISING); else attachInterrupt(digitalPinToInterrupt(WINDSPEEDCOUNTER_PIN), windspeedcounterISR, RISING); 826 | } 827 | 828 | void loop() { 829 | bool worked = hal.runready(); 830 | bool poll = sdev.pollRadio(); 831 | if ( worked == false && poll == false ) { 832 | // hal.activity.savePower>(hal); 833 | } 834 | } 835 | -------------------------------------------------------------------------------- /I2C.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | I2C.cpp - I2C library 3 | Copyright (c) 2011-2012 Wayne Truchsess. All right reserved. 4 | Rev 5.0 - January 24th, 2012 5 | - Removed the use of interrupts completely from the library 6 | so TWI state changes are now polled. 7 | - Added calls to lockup() function in most functions 8 | to combat arbitration problems 9 | - Fixed scan() procedure which left timeouts enabled 10 | and set to 80msec after exiting procedure 11 | - Changed scan() address range back to 0 - 0x7F 12 | - Removed all Wire legacy functions from library 13 | - A big thanks to Richard Baldwin for all the testing 14 | and feedback with debugging bus lockups! 15 | Rev 4.0 - January 14th, 2012 16 | - Updated to make compatible with 8MHz clock frequency 17 | Rev 3.0 - January 9th, 2012 18 | - Modified library to be compatible with Arduino 1.0 19 | - Changed argument type from boolean to uint8_t in pullUp(), 20 | setSpeed() and receiveByte() functions for 1.0 compatability 21 | - Modified return values for timeout feature to report 22 | back where in the transmission the timeout occured. 23 | - added function scan() to perform a bus scan to find devices 24 | attached to the I2C bus. Similar to work done by Todbot 25 | and Nick Gammon 26 | Rev 2.0 - September 19th, 2011 27 | - Added support for timeout function to prevent 28 | and recover from bus lockup (thanks to PaulS 29 | and CrossRoads on the Arduino forum) 30 | - Changed return type for stop() from void to 31 | uint8_t to handle timeOut function 32 | Rev 1.0 - August 8th, 2011 33 | 34 | This is a modified version of the Arduino Wire/TWI 35 | library. Functions were rewritten to provide more functionality 36 | and also the use of Repeated Start. Some I2C devices will not 37 | function correctly without the use of a Repeated Start. The 38 | initial version of this library only supports the Master. 39 | 40 | 41 | This library is free software; you can redistribute it and/or 42 | modify it under the terms of the GNU Lesser General Public 43 | License as published by the Free Software Foundation; either 44 | version 2.1 of the License, or (at your option) any later version. 45 | 46 | This library is distributed in the hope that it will be useful, 47 | but WITHOUT ANY WARRANTY; without even the implied warranty of 48 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 49 | Lesser General Public License for more details. 50 | 51 | You should have received a copy of the GNU Lesser General Public 52 | License along with this library; if not, write to the Free Software 53 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 54 | */ 55 | 56 | #if(ARDUINO >= 100) 57 | #include 58 | #else 59 | #include 60 | #endif 61 | 62 | #include 63 | #include "I2C.h" 64 | 65 | 66 | 67 | uint8_t I2C::bytesAvailable = 0; 68 | uint8_t I2C::bufferIndex = 0; 69 | uint8_t I2C::totalBytes = 0; 70 | uint16_t I2C::timeOutDelay = 0; 71 | 72 | I2C::I2C() 73 | { 74 | } 75 | 76 | 77 | ////////////// Public Methods //////////////////////////////////////// 78 | 79 | 80 | 81 | void I2C::begin() 82 | { 83 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__) 84 | // activate internal pull-ups for twi 85 | // as per note from atmega8 manual pg167 86 | sbi(PORTC, 4); 87 | sbi(PORTC, 5); 88 | #else 89 | // activate internal pull-ups for twi 90 | // as per note from atmega128 manual pg204 91 | sbi(PORTD, 0); 92 | sbi(PORTD, 1); 93 | #endif 94 | // initialize twi prescaler and bit rate 95 | cbi(TWSR, TWPS0); 96 | cbi(TWSR, TWPS1); 97 | TWBR = ((F_CPU / 100000) - 16) / 2; 98 | // enable twi module and acks 99 | TWCR = _BV(TWEN) | _BV(TWEA); 100 | } 101 | 102 | void I2C::end() 103 | { 104 | TWCR = 0; 105 | } 106 | 107 | void I2C::timeOut(uint16_t _timeOut) 108 | { 109 | timeOutDelay = _timeOut; 110 | } 111 | 112 | void I2C::setSpeed(uint8_t _fast) 113 | { 114 | if(!_fast) 115 | { 116 | TWBR = ((F_CPU / 100000) - 16) / 2; 117 | } 118 | else 119 | { 120 | TWBR = ((F_CPU / 400000) - 16) / 2; 121 | } 122 | } 123 | 124 | void I2C::pullup(uint8_t activate) 125 | { 126 | if(activate) 127 | { 128 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__) 129 | // activate internal pull-ups for twi 130 | // as per note from atmega8 manual pg167 131 | sbi(PORTC, 4); 132 | sbi(PORTC, 5); 133 | #else 134 | // activate internal pull-ups for twi 135 | // as per note from atmega128 manual pg204 136 | sbi(PORTD, 0); 137 | sbi(PORTD, 1); 138 | #endif 139 | } 140 | else 141 | { 142 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__) 143 | // deactivate internal pull-ups for twi 144 | // as per note from atmega8 manual pg167 145 | cbi(PORTC, 4); 146 | cbi(PORTC, 5); 147 | #else 148 | // deactivate internal pull-ups for twi 149 | // as per note from atmega128 manual pg204 150 | cbi(PORTD, 0); 151 | cbi(PORTD, 1); 152 | #endif 153 | } 154 | } 155 | 156 | void I2C::scan() 157 | { 158 | uint16_t tempTime = timeOutDelay; 159 | timeOut(80); 160 | uint8_t totalDevicesFound = 0; 161 | Serial.println("Scanning for devices...please wait"); 162 | Serial.println(); 163 | for(uint8_t s = 0; s <= 0x7F; s++) 164 | { 165 | returnStatus = 0; 166 | returnStatus = start(); 167 | if(!returnStatus) 168 | { 169 | returnStatus = sendAddress(SLA_W(s)); 170 | } 171 | if(returnStatus) 172 | { 173 | if(returnStatus == 1) 174 | { 175 | Serial.println("There is a problem with the bus, could not complete scan"); 176 | timeOutDelay = tempTime; 177 | return; 178 | } 179 | } 180 | else 181 | { 182 | Serial.print("Found device at address - "); 183 | Serial.print(" 0x"); 184 | Serial.println(s,HEX); 185 | totalDevicesFound++; 186 | } 187 | stop(); 188 | } 189 | if(!totalDevicesFound){Serial.println("No devices found");} 190 | timeOutDelay = tempTime; 191 | } 192 | 193 | 194 | uint8_t I2C::available() 195 | { 196 | return(bytesAvailable); 197 | } 198 | 199 | uint8_t I2C::receive() 200 | { 201 | bufferIndex = totalBytes - bytesAvailable; 202 | if(!bytesAvailable) 203 | { 204 | bufferIndex = 0; 205 | return(0); 206 | } 207 | bytesAvailable--; 208 | return(data[bufferIndex]); 209 | } 210 | 211 | 212 | /*return values for new functions that use the timeOut feature 213 | will now return at what point in the transmission the timeout 214 | occurred. Looking at a full communication sequence between a 215 | master and slave (transmit data and then readback data) there 216 | a total of 7 points in the sequence where a timeout can occur. 217 | These are listed below and correspond to the returned value: 218 | 1 - Waiting for successful completion of a Start bit 219 | 2 - Waiting for ACK/NACK while addressing slave in transmit mode (MT) 220 | 3 - Waiting for ACK/NACK while sending data to the slave 221 | 4 - Waiting for successful completion of a Repeated Start 222 | 5 - Waiting for ACK/NACK while addressing slave in receiver mode (MR) 223 | 6 - Waiting for ACK/NACK while receiving data from the slave 224 | 7 - Waiting for successful completion of the Stop bit 225 | 226 | All possible return values: 227 | 0 Function executed with no errors 228 | 1 - 7 Timeout occurred, see above list 229 | 8 - 0xFF See datasheet for exact meaning */ 230 | 231 | 232 | ///////////////////////////////////////////////////// 233 | 234 | uint8_t I2C::write(uint8_t address, uint8_t registerAddress) 235 | { 236 | returnStatus = 0; 237 | returnStatus = start(); 238 | if(returnStatus){return(returnStatus);} 239 | returnStatus = sendAddress(SLA_W(address)); 240 | if(returnStatus) 241 | { 242 | if(returnStatus == 1){return(2);} 243 | return(returnStatus); 244 | } 245 | returnStatus = sendByte(registerAddress); 246 | if(returnStatus) 247 | { 248 | if(returnStatus == 1){return(3);} 249 | return(returnStatus); 250 | } 251 | returnStatus = stop(); 252 | if(returnStatus) 253 | { 254 | if(returnStatus == 1){return(7);} 255 | return(returnStatus); 256 | } 257 | return(returnStatus); 258 | } 259 | 260 | uint8_t I2C::write(int address, int registerAddress) 261 | { 262 | return(write((uint8_t) address, (uint8_t) registerAddress)); 263 | } 264 | 265 | uint8_t I2C::write(uint8_t address, uint8_t registerAddress, uint8_t data) 266 | { 267 | returnStatus = 0; 268 | returnStatus = start(); 269 | if(returnStatus){return(returnStatus);} 270 | returnStatus = sendAddress(SLA_W(address)); 271 | if(returnStatus) 272 | { 273 | if(returnStatus == 1){return(2);} 274 | return(returnStatus); 275 | } 276 | returnStatus = sendByte(registerAddress); 277 | if(returnStatus) 278 | { 279 | if(returnStatus == 1){return(3);} 280 | return(returnStatus); 281 | } 282 | returnStatus = sendByte(data); 283 | if(returnStatus) 284 | { 285 | if(returnStatus == 1){return(3);} 286 | return(returnStatus); 287 | } 288 | returnStatus = stop(); 289 | if(returnStatus) 290 | { 291 | if(returnStatus == 1){return(7);} 292 | return(returnStatus); 293 | } 294 | return(returnStatus); 295 | } 296 | 297 | uint8_t I2C::write(int address, int registerAddress, int data) 298 | { 299 | return(write((uint8_t) address, (uint8_t) registerAddress, (uint8_t) data)); 300 | } 301 | 302 | uint8_t I2C::write(uint8_t address, uint8_t registerAddress, char *data) 303 | { 304 | uint8_t bufferLength = strlen(data); 305 | returnStatus = 0; 306 | returnStatus = write(address, registerAddress, (uint8_t*)data, bufferLength); 307 | return(returnStatus); 308 | } 309 | 310 | uint8_t I2C::write(uint8_t address, uint8_t registerAddress, uint8_t *data, uint8_t numberBytes) 311 | { 312 | returnStatus = 0; 313 | returnStatus = start(); 314 | if(returnStatus){return(returnStatus);} 315 | returnStatus = sendAddress(SLA_W(address)); 316 | if(returnStatus) 317 | { 318 | if(returnStatus == 1){return(2);} 319 | return(returnStatus); 320 | } 321 | returnStatus = sendByte(registerAddress); 322 | if(returnStatus) 323 | { 324 | if(returnStatus == 1){return(3);} 325 | return(returnStatus); 326 | } 327 | for (uint8_t i = 0; i < numberBytes; i++) 328 | { 329 | returnStatus = sendByte(data[i]); 330 | if(returnStatus) 331 | { 332 | if(returnStatus == 1){return(3);} 333 | return(returnStatus); 334 | } 335 | } 336 | returnStatus = stop(); 337 | if(returnStatus) 338 | { 339 | if(returnStatus == 1){return(7);} 340 | return(returnStatus); 341 | } 342 | return(returnStatus); 343 | } 344 | 345 | uint8_t I2C::read(int address, int numberBytes) 346 | { 347 | return(read((uint8_t) address, (uint8_t) numberBytes)); 348 | } 349 | 350 | uint8_t I2C::read(uint8_t address, uint8_t numberBytes) 351 | { 352 | bytesAvailable = 0; 353 | bufferIndex = 0; 354 | if(numberBytes == 0){numberBytes++;} 355 | nack = numberBytes - 1; 356 | returnStatus = 0; 357 | returnStatus = start(); 358 | if(returnStatus){return(returnStatus);} 359 | returnStatus = sendAddress(SLA_R(address)); 360 | if(returnStatus) 361 | { 362 | if(returnStatus == 1){return(5);} 363 | return(returnStatus); 364 | } 365 | for(uint8_t i = 0; i < numberBytes; i++) 366 | { 367 | if( i == nack ) 368 | { 369 | returnStatus = receiveByte(0); 370 | if(returnStatus == 1){return(6);} 371 | 372 | if(returnStatus != MR_DATA_NACK){return(returnStatus);} 373 | } 374 | else 375 | { 376 | returnStatus = receiveByte(1); 377 | if(returnStatus == 1){return(6);} 378 | if(returnStatus != MR_DATA_ACK){return(returnStatus);} 379 | } 380 | data[i] = TWDR; 381 | bytesAvailable = i+1; 382 | totalBytes = i+1; 383 | } 384 | returnStatus = stop(); 385 | if(returnStatus) 386 | { 387 | if(returnStatus == 1){return(7);} 388 | return(returnStatus); 389 | } 390 | return(returnStatus); 391 | } 392 | 393 | uint8_t I2C::read(int address, int registerAddress, int numberBytes) 394 | { 395 | return(read((uint8_t) address, (uint8_t) registerAddress, (uint8_t) numberBytes)); 396 | } 397 | 398 | uint8_t I2C::read(uint8_t address, uint8_t registerAddress, uint8_t numberBytes) 399 | { 400 | bytesAvailable = 0; 401 | bufferIndex = 0; 402 | if(numberBytes == 0){numberBytes++;} 403 | nack = numberBytes - 1; 404 | returnStatus = 0; 405 | returnStatus = start(); 406 | if(returnStatus){return(returnStatus);} 407 | returnStatus = sendAddress(SLA_W(address)); 408 | if(returnStatus) 409 | { 410 | if(returnStatus == 1){return(2);} 411 | return(returnStatus); 412 | } 413 | returnStatus = sendByte(registerAddress); 414 | if(returnStatus) 415 | { 416 | if(returnStatus == 1){return(3);} 417 | return(returnStatus); 418 | } 419 | returnStatus = start(); 420 | if(returnStatus) 421 | { 422 | if(returnStatus == 1){return(4);} 423 | return(returnStatus); 424 | } 425 | returnStatus = sendAddress(SLA_R(address)); 426 | if(returnStatus) 427 | { 428 | if(returnStatus == 1){return(5);} 429 | return(returnStatus); 430 | } 431 | for(uint8_t i = 0; i < numberBytes; i++) 432 | { 433 | if( i == nack ) 434 | { 435 | returnStatus = receiveByte(0); 436 | if(returnStatus == 1){return(6);} 437 | if(returnStatus != MR_DATA_NACK){return(returnStatus);} 438 | } 439 | else 440 | { 441 | returnStatus = receiveByte(1); 442 | if(returnStatus == 1){return(6);} 443 | if(returnStatus != MR_DATA_ACK){return(returnStatus);} 444 | } 445 | data[i] = TWDR; 446 | bytesAvailable = i+1; 447 | totalBytes = i+1; 448 | } 449 | returnStatus = stop(); 450 | if(returnStatus) 451 | { 452 | if(returnStatus == 1){return(7);} 453 | return(returnStatus); 454 | } 455 | return(returnStatus); 456 | } 457 | 458 | uint8_t I2C::read(uint8_t address, uint8_t numberBytes, uint8_t *dataBuffer) 459 | { 460 | bytesAvailable = 0; 461 | bufferIndex = 0; 462 | if(numberBytes == 0){numberBytes++;} 463 | nack = numberBytes - 1; 464 | returnStatus = 0; 465 | returnStatus = start(); 466 | if(returnStatus){return(returnStatus);} 467 | returnStatus = sendAddress(SLA_R(address)); 468 | if(returnStatus) 469 | { 470 | if(returnStatus == 1){return(5);} 471 | return(returnStatus); 472 | } 473 | for(uint8_t i = 0; i < numberBytes; i++) 474 | { 475 | if( i == nack ) 476 | { 477 | returnStatus = receiveByte(0); 478 | if(returnStatus == 1){return(6);} 479 | if(returnStatus != MR_DATA_NACK){return(returnStatus);} 480 | } 481 | else 482 | { 483 | returnStatus = receiveByte(1); 484 | if(returnStatus == 1){return(6);} 485 | if(returnStatus != MR_DATA_ACK){return(returnStatus);} 486 | } 487 | dataBuffer[i] = TWDR; 488 | bytesAvailable = i+1; 489 | totalBytes = i+1; 490 | } 491 | returnStatus = stop(); 492 | if(returnStatus) 493 | { 494 | if(returnStatus == 1){return(7);} 495 | return(returnStatus); 496 | } 497 | return(returnStatus); 498 | } 499 | 500 | uint8_t I2C::read(uint8_t address, uint8_t registerAddress, uint8_t numberBytes, uint8_t *dataBuffer) 501 | { 502 | bytesAvailable = 0; 503 | bufferIndex = 0; 504 | if(numberBytes == 0){numberBytes++;} 505 | nack = numberBytes - 1; 506 | returnStatus = 0; 507 | returnStatus = start(); 508 | if(returnStatus){return(returnStatus);} 509 | returnStatus = sendAddress(SLA_W(address)); 510 | if(returnStatus) 511 | { 512 | if(returnStatus == 1){return(2);} 513 | return(returnStatus); 514 | } 515 | returnStatus = sendByte(registerAddress); 516 | if(returnStatus) 517 | { 518 | if(returnStatus == 1){return(3);} 519 | return(returnStatus); 520 | } 521 | returnStatus = start(); 522 | if(returnStatus) 523 | { 524 | if(returnStatus == 1){return(4);} 525 | return(returnStatus); 526 | } 527 | returnStatus = sendAddress(SLA_R(address)); 528 | if(returnStatus) 529 | { 530 | if(returnStatus == 1){return(5);} 531 | return(returnStatus); 532 | } 533 | for(uint8_t i = 0; i < numberBytes; i++) 534 | { 535 | if( i == nack ) 536 | { 537 | returnStatus = receiveByte(0); 538 | if(returnStatus == 1){return(6);} 539 | if(returnStatus != MR_DATA_NACK){return(returnStatus);} 540 | } 541 | else 542 | { 543 | returnStatus = receiveByte(1); 544 | if(returnStatus == 1){return(6);} 545 | if(returnStatus != MR_DATA_ACK){return(returnStatus);} 546 | } 547 | dataBuffer[i] = TWDR; 548 | bytesAvailable = i+1; 549 | totalBytes = i+1; 550 | } 551 | returnStatus = stop(); 552 | if(returnStatus) 553 | { 554 | if(returnStatus == 1){return(7);} 555 | return(returnStatus); 556 | } 557 | return(returnStatus); 558 | } 559 | 560 | 561 | /////////////// Private Methods //////////////////////////////////////// 562 | 563 | 564 | uint8_t I2C::start() 565 | { 566 | unsigned long startingTime = millis(); 567 | TWCR = (1<= timeOutDelay) 572 | { 573 | lockUp(); 574 | return(1); 575 | } 576 | 577 | } 578 | if ((TWI_STATUS == START) || (TWI_STATUS == REPEATED_START)) 579 | { 580 | return(0); 581 | } 582 | if (TWI_STATUS == LOST_ARBTRTN) 583 | { 584 | uint8_t bufferedStatus = TWI_STATUS; 585 | lockUp(); 586 | return(bufferedStatus); 587 | } 588 | return(TWI_STATUS); 589 | } 590 | 591 | uint8_t I2C::sendAddress(uint8_t i2cAddress) 592 | { 593 | TWDR = i2cAddress; 594 | unsigned long startingTime = millis(); 595 | TWCR = (1<= timeOutDelay) 600 | { 601 | lockUp(); 602 | return(1); 603 | } 604 | 605 | } 606 | if ((TWI_STATUS == MT_SLA_ACK) || (TWI_STATUS == MR_SLA_ACK)) 607 | { 608 | return(0); 609 | } 610 | uint8_t bufferedStatus = TWI_STATUS; 611 | if ((TWI_STATUS == MT_SLA_NACK) || (TWI_STATUS == MR_SLA_NACK)) 612 | { 613 | stop(); 614 | return(bufferedStatus); 615 | } 616 | else 617 | { 618 | lockUp(); 619 | return(bufferedStatus); 620 | } 621 | } 622 | 623 | uint8_t I2C::sendByte(uint8_t i2cData) 624 | { 625 | TWDR = i2cData; 626 | unsigned long startingTime = millis(); 627 | TWCR = (1<= timeOutDelay) 632 | { 633 | lockUp(); 634 | return(1); 635 | } 636 | 637 | } 638 | if (TWI_STATUS == MT_DATA_ACK) 639 | { 640 | return(0); 641 | } 642 | uint8_t bufferedStatus = TWI_STATUS; 643 | if (TWI_STATUS == MT_DATA_NACK) 644 | { 645 | stop(); 646 | return(bufferedStatus); 647 | } 648 | else 649 | { 650 | lockUp(); 651 | return(bufferedStatus); 652 | } 653 | } 654 | 655 | uint8_t I2C::receiveByte(uint8_t ack) 656 | { 657 | unsigned long startingTime = millis(); 658 | if(ack) 659 | { 660 | TWCR = (1<= timeOutDelay) 671 | { 672 | lockUp(); 673 | return(1); 674 | } 675 | } 676 | if (TWI_STATUS == LOST_ARBTRTN) 677 | { 678 | uint8_t bufferedStatus = TWI_STATUS; 679 | lockUp(); 680 | return(bufferedStatus); 681 | } 682 | return(TWI_STATUS); 683 | } 684 | 685 | uint8_t I2C::stop() 686 | { 687 | unsigned long startingTime = millis(); 688 | TWCR = (1<= timeOutDelay) 693 | { 694 | lockUp(); 695 | return(1); 696 | } 697 | 698 | } 699 | return(0); 700 | } 701 | 702 | void I2C::lockUp() 703 | { 704 | TWCR = 0; //releases SDA and SCL lines to high impedance 705 | TWCR = _BV(TWEN) | _BV(TWEA); //reinitialize TWI 706 | } 707 | 708 | I2C I2c = I2C(); 709 | 710 | -------------------------------------------------------------------------------- /I2C.h: -------------------------------------------------------------------------------- 1 | /* 2 | I2C.h - I2C library 3 | Copyright (c) 2011-2012 Wayne Truchsess. All right reserved. 4 | Rev 5.0 - January 24th, 2012 5 | - Removed the use of interrupts completely from the library 6 | so TWI state changes are now polled. 7 | - Added calls to lockup() function in most functions 8 | to combat arbitration problems 9 | - Fixed scan() procedure which left timeouts enabled 10 | and set to 80msec after exiting procedure 11 | - Changed scan() address range back to 0 - 0x7F 12 | - Removed all Wire legacy functions from library 13 | - A big thanks to Richard Baldwin for all the testing 14 | and feedback with debugging bus lockups! 15 | Rev 4.0 - January 14th, 2012 16 | - Updated to make compatible with 8MHz clock frequency 17 | Rev 3.0 - January 9th, 2012 18 | - Modified library to be compatible with Arduino 1.0 19 | - Changed argument type from boolean to uint8_t in pullUp(), 20 | setSpeed() and receiveByte() functions for 1.0 compatability 21 | - Modified return values for timeout feature to report 22 | back where in the transmission the timeout occured. 23 | - added function scan() to perform a bus scan to find devices 24 | attached to the I2C bus. Similar to work done by Todbot 25 | and Nick Gammon 26 | Rev 2.0 - September 19th, 2011 27 | - Added support for timeout function to prevent 28 | and recover from bus lockup (thanks to PaulS 29 | and CrossRoads on the Arduino forum) 30 | - Changed return type for stop() from void to 31 | uint8_t to handle timeOut function 32 | Rev 1.0 - August 8th, 2011 33 | 34 | This is a modified version of the Arduino Wire/TWI 35 | library. Functions were rewritten to provide more functionality 36 | and also the use of Repeated Start. Some I2C devices will not 37 | function correctly without the use of a Repeated Start. The 38 | initial version of this library only supports the Master. 39 | 40 | 41 | This library is free software; you can redistribute it and/or 42 | modify it under the terms of the GNU Lesser General Public 43 | License as published by the Free Software Foundation; either 44 | version 2.1 of the License, or (at your option) any later version. 45 | 46 | This library is distributed in the hope that it will be useful, 47 | but WITHOUT ANY WARRANTY; without even the implied warranty of 48 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 49 | Lesser General Public License for more details. 50 | 51 | You should have received a copy of the GNU Lesser General Public 52 | License along with this library; if not, write to the Free Software 53 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 54 | */ 55 | 56 | #if(ARDUINO >= 100) 57 | #include 58 | #else 59 | #include 60 | #endif 61 | 62 | #include 63 | 64 | #ifndef I2C_h 65 | #define I2C_h 66 | 67 | 68 | #define START 0x08 69 | #define REPEATED_START 0x10 70 | #define MT_SLA_ACK 0x18 71 | #define MT_SLA_NACK 0x20 72 | #define MT_DATA_ACK 0x28 73 | #define MT_DATA_NACK 0x30 74 | #define MR_SLA_ACK 0x40 75 | #define MR_SLA_NACK 0x48 76 | #define MR_DATA_ACK 0x50 77 | #define MR_DATA_NACK 0x58 78 | #define LOST_ARBTRTN 0x38 79 | #define TWI_STATUS (TWSR & 0xF8) 80 | #define SLA_W(address) (address << 1) 81 | #define SLA_R(address) ((address << 1) + 0x01) 82 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 83 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 84 | 85 | #define MAX_BUFFER_SIZE 32 86 | 87 | 88 | 89 | 90 | class I2C 91 | { 92 | public: 93 | I2C(); 94 | void begin(); 95 | void end(); 96 | void timeOut(uint16_t); 97 | void setSpeed(uint8_t); 98 | void pullup(uint8_t); 99 | void scan(); 100 | uint8_t available(); 101 | uint8_t receive(); 102 | uint8_t write(uint8_t, uint8_t); 103 | uint8_t write(int, int); 104 | uint8_t write(uint8_t, uint8_t, uint8_t); 105 | uint8_t write(int, int, int); 106 | uint8_t write(uint8_t, uint8_t, char*); 107 | uint8_t write(uint8_t, uint8_t, uint8_t*, uint8_t); 108 | uint8_t read(uint8_t, uint8_t); 109 | uint8_t read(int, int); 110 | uint8_t read(uint8_t, uint8_t, uint8_t); 111 | uint8_t read(int, int, int); 112 | uint8_t read(uint8_t, uint8_t, uint8_t*); 113 | uint8_t read(uint8_t, uint8_t, uint8_t, uint8_t*); 114 | 115 | 116 | private: 117 | uint8_t start(); 118 | uint8_t sendAddress(uint8_t); 119 | uint8_t sendByte(uint8_t); 120 | uint8_t receiveByte(uint8_t); 121 | uint8_t stop(); 122 | void lockUp(); 123 | uint8_t returnStatus; 124 | uint8_t nack; 125 | uint8_t data[MAX_BUFFER_SIZE]; 126 | static uint8_t bytesAvailable; 127 | static uint8_t bufferIndex; 128 | static uint8_t totalBytes; 129 | static uint16_t timeOutDelay; 130 | 131 | }; 132 | 133 | extern I2C I2c; 134 | 135 | #endif 136 | -------------------------------------------------------------------------------- /Images/0.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/0.JPG -------------------------------------------------------------------------------- /Images/1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/1.JPG -------------------------------------------------------------------------------- /Images/2.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/2.JPG -------------------------------------------------------------------------------- /Images/3.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/3.JPG -------------------------------------------------------------------------------- /Images/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/4.png -------------------------------------------------------------------------------- /Images/Arduino_Boardverwaltung.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/Arduino_Boardverwaltung.png -------------------------------------------------------------------------------- /Images/BME_PFTE.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/BME_PFTE.jpeg -------------------------------------------------------------------------------- /Images/CCU_Addon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/CCU_Addon.png -------------------------------------------------------------------------------- /Images/CCU_Bedienung.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/CCU_Bedienung.png -------------------------------------------------------------------------------- /Images/CCU_DV_Regen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/CCU_DV_Regen.png -------------------------------------------------------------------------------- /Images/CCU_DV_Sturm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/CCU_DV_Sturm.png -------------------------------------------------------------------------------- /Images/CCU_Einstellungen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/CCU_Einstellungen.png -------------------------------------------------------------------------------- /Images/CCU_Experteneinstellungen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/CCU_Experteneinstellungen.png -------------------------------------------------------------------------------- /Images/CCU_Geraet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/CCU_Geraet.png -------------------------------------------------------------------------------- /Images/Connect_AS3935.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/Connect_AS3935.jpeg -------------------------------------------------------------------------------- /Images/PCB_Connectors.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/PCB_Connectors.jpeg -------------------------------------------------------------------------------- /Images/Platine_bestueckt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/Platine_bestueckt.jpg -------------------------------------------------------------------------------- /Images/as3935_back_rot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/as3935_back_rot.png -------------------------------------------------------------------------------- /Images/sample1_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/sample1_1.jpg -------------------------------------------------------------------------------- /Images/sample1_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/sample1_2.jpg -------------------------------------------------------------------------------- /Images/sample1_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/sample1_3.jpg -------------------------------------------------------------------------------- /Images/wiring.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/wiring.fzz -------------------------------------------------------------------------------- /Images/wiring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Images/wiring.png -------------------------------------------------------------------------------- /Luftdruck_Tendenz.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Luftdruck_Tendenz.txt -------------------------------------------------------------------------------- /PWFusion_AS3935.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright © 2014 Playing With Fusion, Inc. 2 | SOFTWARE LICENSE AGREEMENT: This code is released under the MIT License. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | * ************************************************************************** 22 | REVISION HISTORY: 23 | Author Date Comments 24 | J. Steinlage 2014Aug20 Original version 25 | J. Steinlage 2016Jul05 Fixed data write issue - now writing 'NewRegData' 26 | based on feedback from J Shuhy and A Jahnke 27 | 28 | jp112sdl 2018Jun21 modified for the use with AskSinPP (using SPI transactions) 29 | 30 | */ 31 | #include 32 | #include "PWFusion_AS3935.h" 33 | #define _SPI_CLOCK_DIVIDER SPI_CLOCK_DIV8 34 | #define _SPI_DATA_MODE SPI_MODE1 35 | #define _SPI_BIT_ORDER MSBFIRST 36 | 37 | PWF_AS3935::PWF_AS3935(uint8_t CSx, uint8_t IRQx) 38 | { 39 | _cs = CSx; 40 | _irq = IRQx; 41 | 42 | // initalize the chip select pins 43 | pinMode(_cs, OUTPUT); 44 | pinMode(_irq, INPUT); 45 | 46 | digitalWrite(_cs, HIGH); // set pin high to initialize/clear SPI bus 47 | } 48 | 49 | uint8_t PWF_AS3935::_sing_reg_read(uint8_t RegAdd) 50 | { 51 | digitalWrite(_cs, LOW); // set pin low to start talking to IC 52 | // next pack command byte, send AS3935.... structure is shown below 53 | // MODE Register Address/Direct Cmd 54 | // B15-14 B13------------------8 55 | // 15 is always 0; B14, 0: Write/Direct Command, 1: Read 56 | SPI.beginTransaction(SPISettings(_SPI_CLOCK_DIVIDER, _SPI_BIT_ORDER, _SPI_DATA_MODE)); 57 | SPI.transfer((RegAdd & 0x3F) | 0x40); // simple write, nothing to read back 58 | SPI.endTransaction(); 59 | uint8_t RegData = SPI.transfer(0x00); // read register data from IC 60 | digitalWrite(_cs, HIGH); // set pin high to end SPI session 61 | 62 | return RegData; 63 | } 64 | 65 | void PWF_AS3935::_sing_reg_write(uint8_t RegAdd, uint8_t DataMask, uint8_t RegData) 66 | { 67 | // start by reading original register data (only modifying what we need to) 68 | uint8_t OrigRegData = _sing_reg_read(RegAdd); 69 | 70 | // calculate new register data... 'delete' old targeted data, replace with new data 71 | // note: 'DataMask' must be bits targeted for replacement 72 | // add'l note: this function does NOT shift values into the proper place... they need to be there already 73 | uint8_t NewRegData = ((OrigRegData & ~DataMask) | (RegData & DataMask)); 74 | 75 | // now configure and write the updated register value 76 | digitalWrite(_cs, LOW); // set pin low to start talking to IC 77 | // next pack command byte, send AS3935.... structure is shown below 78 | // MODE Register Address/Direct Cmd 79 | // B15-14 B13------------------8 80 | // 15 is always 0; B14, 0: Write/Direct Command, 1: Read 81 | SPI.beginTransaction(SPISettings(_SPI_CLOCK_DIVIDER, _SPI_BIT_ORDER, _SPI_DATA_MODE)); 82 | SPI.transfer((RegAdd & 0x3F)); // simple write, nothing to read back 83 | SPI.transfer(NewRegData); // write register data to IC 84 | SPI.endTransaction(); 85 | digitalWrite(_cs, HIGH); // set pin high to end SPI session 86 | } 87 | 88 | 89 | void PWF_AS3935::AS3935_Reset() 90 | { 91 | digitalWrite(_cs, LOW); // begin transfer 92 | // run PRESET_DEFAULT Direct Command to set all registers in default state 93 | SPI.beginTransaction(SPISettings(_SPI_CLOCK_DIVIDER, _SPI_BIT_ORDER, _SPI_DATA_MODE)); 94 | SPI.transfer(0x3C); // send first byte (write, PRESET_DEFAULT register) 95 | SPI.transfer(0x96); // send second byte (direct command) 96 | SPI.endTransaction(); 97 | digitalWrite(_cs, HIGH); // end transfer 98 | delay(2); // wait 2ms to complete 99 | } 100 | 101 | void PWF_AS3935::_CalRCO() 102 | { 103 | // run ALIB_RCO Direct Command to cal internal RCO 104 | digitalWrite(_cs, LOW); // begin transfer 105 | SPI.beginTransaction(SPISettings(_SPI_CLOCK_DIVIDER, _SPI_BIT_ORDER, _SPI_DATA_MODE)); 106 | SPI.transfer(0x3D); // send first byte (write, CALIB_RCO register) 107 | SPI.transfer(0x96); // send second byte (direct command) 108 | SPI.endTransaction(); 109 | digitalWrite(_cs, HIGH); // end transfer 110 | delay(3); // wait 3ms to complete 111 | } 112 | 113 | void PWF_AS3935::AS3935_PowerUp(void) 114 | { 115 | // power-up sequence based on datasheet, pg 23/27 116 | // register 0x00, PWD bit: 0 (clears PWD) 117 | _sing_reg_write(0x00, 0x01, 0x00); 118 | _CalRCO(); // run RCO cal cmd 119 | _sing_reg_write(0x08, 0x20, 0x20); // set DISP_SRCO to 1 120 | delay(2); 121 | _sing_reg_write(0x08, 0x20, 0x00); // set DISP_SRCO to 0 122 | 123 | } 124 | 125 | void PWF_AS3935::AS3935_DisturberEn(void) 126 | { 127 | // register 0x03, PWD bit: 5 (sets MASK_DIST) 128 | _sing_reg_write(0x03, 0x20, 0x00); 129 | //DPRINTLN("LD DIST DETECT EN"); 130 | } 131 | 132 | void PWF_AS3935::AS3935_DisturberDis(void) 133 | { 134 | // register 0x03, PWD bit: 5 (sets MASK_DIST) 135 | _sing_reg_write(0x03, 0x20, 0x20); 136 | //DPRINTLN("LD: DIST DETECT DIS"); 137 | } 138 | 139 | void PWF_AS3935::AS3935_SetIRQ_Output_Source(uint8_t irq_select) 140 | { 141 | // set interrupt source - what to displlay on IRQ pin 142 | // reg 0x08, bits 5 (TRCO), 6 (SRCO), 7 (LCO) 143 | // only one should be set at once, I think 144 | // 0 = NONE, 1 = TRCO, 2 = SRCO, 3 = LCO 145 | 146 | if (1 == irq_select) 147 | { 148 | _sing_reg_write(0x08, 0xE0, 0x20); // set only TRCO bit 149 | } 150 | else if (2 == irq_select) 151 | { 152 | _sing_reg_write(0x08, 0xE0, 0x40); // set only SRCO bit 153 | } 154 | else if (3 == irq_select) 155 | { 156 | _sing_reg_write(0x08, 0xE0, 0x80); // set only LCO bit 157 | } 158 | else // assume 0 159 | { 160 | _sing_reg_write(0x08, 0xE0, 0x00); // clear IRQ pin display bits 161 | } 162 | 163 | } 164 | 165 | void PWF_AS3935::AS3935_SetTuningCaps(uint8_t cap_val) 166 | { 167 | // Assume only numbers divisible by 8 (because that's all the chip supports) 168 | if (120 < cap_val) // cap_value out of range, assume highest capacitance 169 | { 170 | _sing_reg_write(0x08, 0x0F, 0x0F); // set capacitance bits to maximum 171 | } 172 | else 173 | { 174 | _sing_reg_write(0x08, 0x0F, (cap_val >> 3)); // set capacitance bits 175 | } 176 | //DPRINT("LD CAP SET TO 0x"); 177 | //DPRINTLN((_sing_reg_read(0x08) & 0x0F)); 178 | } 179 | 180 | uint8_t PWF_AS3935::AS3935_GetInterruptSrc(void) 181 | { 182 | // definition of interrupt data on table 18 of datasheet 183 | // for this function: 184 | // 0 = unknown src, 1 = lightning detected, 2 = disturber, 3 = Noise level too high 185 | delay(10); // wait 10ms before reading (2ms per pg 22 of datasheet) 186 | uint8_t int_src = (_sing_reg_read(0x03) & 0x0F); // read register, get rid of non-interrupt data 187 | if (0x08 == int_src) 188 | { 189 | return 1; // lightning caused interrupt 190 | } 191 | else if (0x04 == int_src) 192 | { 193 | return 2; // disturber detected 194 | } 195 | else if (0x01 == int_src) 196 | { 197 | return 3; // Noise level too high 198 | } 199 | else { 200 | return 0; // interrupt result not expected 201 | } 202 | 203 | } 204 | 205 | uint8_t PWF_AS3935::AS3935_GetLightningDistKm(void) 206 | { 207 | uint8_t strike_dist = ((_sing_reg_read(0x07)) & 0x3F); // read register, get rid of non-distance data 208 | return strike_dist; 209 | } 210 | 211 | uint32_t PWF_AS3935::AS3935_GetStrikeEnergyRaw(void) 212 | { 213 | uint32_t nrgy_raw = ((_sing_reg_read(0x06) & 0x1F) << 8); // MMSB, shift 8 bits left, make room for MSB 214 | nrgy_raw |= _sing_reg_read(0x05); // read MSB 215 | nrgy_raw <<= 8; // shift 8 bits left, make room for LSB 216 | nrgy_raw |= _sing_reg_read(0x04); // read LSB, add to others 217 | 218 | return nrgy_raw; 219 | } 220 | 221 | uint8_t PWF_AS3935::AS3935_SetMinStrikes(uint8_t min_strk) 222 | { 223 | // This function sets min strikes to the closest available number, rounding to the floor, 224 | // where necessary, then returns the physical value that was set. Options are 1, 5, 9 or 16 strikes. 225 | // see pg 22 of the datasheet for more info (#strikes in 17 min) 226 | if (5 > min_strk) 227 | { 228 | _sing_reg_write(0x02, 0x30, 0x00); 229 | return 1; 230 | } 231 | else if (9 > min_strk) 232 | { 233 | _sing_reg_write(0x02, 0x30, 0x10); 234 | return 5; 235 | } 236 | else if (16 > min_strk) 237 | { 238 | _sing_reg_write(0x02, 0x30, 0x20); 239 | return 9; 240 | } 241 | else 242 | { 243 | _sing_reg_write(0x02, 0x30, 0x30); 244 | return 16; 245 | } 246 | } 247 | 248 | void PWF_AS3935::AS3935_SetIndoors(void) 249 | { 250 | // AFE settings addres 0x00, bits 5:1 (10010, based on datasheet, pg 19, table 15) 251 | // this is the default setting at power-up (AS3935 datasheet, table 9) 252 | _sing_reg_write(0x00, 0x3E, 0x24); 253 | } 254 | 255 | void PWF_AS3935::AS3935_SetOutdoors(void) 256 | { 257 | // AFE settings addres 0x00, bits 5:1 (01110, based on datasheet, pg 19, table 15) 258 | _sing_reg_write(0x00, 0x3E, 0x1C); 259 | } 260 | 261 | void PWF_AS3935::AS3935_ClearStatistics(void) 262 | { 263 | // clear is accomplished by toggling CL_STAT bit 'high-low-high' (then set low to move on) 264 | _sing_reg_write(0x02, 0x40, 0x40); // high 265 | _sing_reg_write(0x02, 0x40, 0x00); // low 266 | _sing_reg_write(0x02, 0x40, 0x40); // high 267 | } 268 | 269 | uint8_t PWF_AS3935::AS3935_GetNoiseFloorLvl(void) 270 | { 271 | // NF settings addres 0x01, bits 6:4 272 | // default setting of 010 at startup (datasheet, table 9) 273 | uint8_t reg_raw = _sing_reg_read(0x01); // read register 0x01 274 | return ((reg_raw & 0x70) >> 4); // should return value from 0-7, see table 16 for info 275 | } 276 | 277 | void PWF_AS3935::AS3935_SetNoiseFloorLvl(uint8_t nf_sel) 278 | { 279 | // NF settings addres 0x01, bits 6:4 280 | // default setting of 010 at startup (datasheet, table 9) 281 | if (7 >= nf_sel) // nf_sel within expected range 282 | { 283 | _sing_reg_write(0x01, 0x70, ((nf_sel & 0x07) << 4)); 284 | } 285 | else 286 | { // out of range, set to default (power-up value 010) 287 | _sing_reg_write(0x01, 0x70, 0x20); 288 | } 289 | } 290 | 291 | uint8_t PWF_AS3935::AS3935_GetWatchdogThreshold(void) 292 | { 293 | // This function is used to read WDTH. It is used to increase robustness to disturbers, 294 | // though will make detection less efficient (see page 19, Fig 20 of datasheet) 295 | // WDTH register: add 0x01, bits 3:0 296 | // default value of 0001 297 | // values should only be between 0x00 and 0x0F (0 and 7) 298 | uint8_t reg_raw = _sing_reg_read(0x01); 299 | return (reg_raw & 0x0F); 300 | } 301 | 302 | void PWF_AS3935::AS3935_SetWatchdogThreshold(uint8_t wdth) 303 | { 304 | // This function is used to modify WDTH. It is used to increase robustness to disturbers, 305 | // though will make detection less efficient (see page 19, Fig 20 of datasheet) 306 | // WDTH register: add 0x01, bits 3:0 307 | // default value of 0001 308 | // values should only be between 0x00 and 0x0F (0 and 7) 309 | _sing_reg_write(0x01, 0x0F, (wdth & 0x0F)); 310 | } 311 | 312 | uint8_t PWF_AS3935::AS3935_GetSpikeRejection(void) 313 | { 314 | // This function is used to read SREJ (spike rejection). Similar to the Watchdog threshold, 315 | // it is used to make the system more robust to disturbers, though will make general detection 316 | // less efficient (see page 20-21, especially Fig 21 of datasheet) 317 | // SREJ register: add 0x02, bits 3:0 318 | // default value of 0010 319 | // values should only be between 0x00 and 0x0F (0 and 7) 320 | uint8_t reg_raw = _sing_reg_read(0x02); 321 | return (reg_raw & 0x0F); 322 | } 323 | 324 | void PWF_AS3935::AS3935_SetSpikeRejection(uint8_t srej) 325 | { 326 | // This function is used to modify SREJ (spike rejection). Similar to the Watchdog threshold, 327 | // it is used to make the system more robust to disturbers, though will make general detection 328 | // less efficient (see page 20-21, especially Fig 21 of datasheet) 329 | // WDTH register: add 0x02, bits 3:0 330 | // default value of 0010 331 | // values should only be between 0x00 and 0x0F (0 and 7) 332 | _sing_reg_write(0x02, 0x0F, (srej & 0x0F)); 333 | } 334 | 335 | void PWF_AS3935::AS3935_SetLCO_FDIV(uint8_t fdiv) 336 | { 337 | // This function sets LCO_FDIV register. This is useful in the tuning of the antenna 338 | // LCO_FDIV register: add 0x03, bits 7:6 339 | // default value: 00 340 | // set 0, 1, 2 or 3 for ratios of 16, 32, 64 and 128, respectively. 341 | // See pg 23, Table 20 for more info. 342 | _sing_reg_write(0x03, 0xC0, ((fdiv & 0x03) << 5)); 343 | } 344 | 345 | void PWF_AS3935::AS3935_PrintAllRegs(void) 346 | { 347 | DPRINT("LD REGS [ "); 348 | DPRINT(_sing_reg_read(0x00)); 349 | DPRINT(" | "); 350 | DPRINT(_sing_reg_read(0x01)); 351 | DPRINT(" | "); 352 | DPRINT(_sing_reg_read(0x02)); 353 | DPRINT(" | "); 354 | DPRINT(_sing_reg_read(0x03)); 355 | DPRINT(" | "); 356 | DPRINT(_sing_reg_read(0x04)); 357 | DPRINT(" | "); 358 | DPRINT(_sing_reg_read(0x05)); 359 | DPRINT(" | "); 360 | DPRINT(_sing_reg_read(0x06)); 361 | DPRINT(" | "); 362 | DPRINT(_sing_reg_read(0x07)); 363 | DPRINT(" | "); 364 | DPRINT(_sing_reg_read(0x08)); 365 | DPRINTLN(" ]"); 366 | } 367 | 368 | void PWF_AS3935::AS3935_ManualCal(uint8_t capacitance, uint8_t disturber, uint8_t environment) 369 | { 370 | AS3935_SetIRQ_Output_Source(0); 371 | 372 | delay(2); 373 | 374 | AS3935_SetTuningCaps(capacitance); 375 | delay(3); 376 | 377 | AS3935_PowerUp(); 378 | 379 | if (0 == environment) { 380 | AS3935_SetOutdoors(); 381 | } else { 382 | AS3935_SetIndoors(); 383 | } 384 | 385 | // disturber cal 386 | if (0 == disturber) { 387 | AS3935_DisturberDis(); 388 | } else { 389 | AS3935_DisturberEn(); 390 | } 391 | 392 | //DPRINTLN("LD CAL COMPLETE"); 393 | } 394 | -------------------------------------------------------------------------------- /PWFusion_AS3935.h: -------------------------------------------------------------------------------- 1 | #ifndef PWF_AS3935_h 2 | #define PWF_AS3935_h 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class PWF_AS3935 11 | { 12 | public: 13 | PWF_AS3935(uint8_t CSx, uint8_t IRQx); 14 | void AS3935_ManualCal(uint8_t capacitance, uint8_t disturber, uint8_t environment); 15 | void AS3935_Reset(void); 16 | void AS3935_PowerUp(void); 17 | void AS3935_PowerDown(void); 18 | void AS3935_DisturberEn(void); 19 | void AS3935_DisturberDis(void); 20 | void AS3935_SetIRQ_Output_Source(uint8_t irq_select); 21 | void AS3935_SetTuningCaps(uint8_t cap_val); 22 | uint8_t AS3935_GetInterruptSrc(void); 23 | uint8_t AS3935_GetLightningDistKm(void); 24 | uint32_t AS3935_GetStrikeEnergyRaw(void); 25 | uint8_t AS3935_SetMinStrikes(uint8_t min_strk); 26 | void AS3935_ClearStatistics(void); 27 | void AS3935_SetOutdoors(void); 28 | void AS3935_SetIndoors(void); 29 | uint8_t AS3935_GetNoiseFloorLvl(void); 30 | void AS3935_SetNoiseFloorLvl(uint8_t nf_sel); 31 | uint8_t AS3935_GetWatchdogThreshold(void); 32 | void AS3935_SetWatchdogThreshold(uint8_t wdth); 33 | uint8_t AS3935_GetSpikeRejection(void); 34 | void AS3935_SetSpikeRejection(uint8_t srej); 35 | void AS3935_SetLCO_FDIV(uint8_t fdiv); 36 | void AS3935_PrintAllRegs(void); 37 | 38 | private: 39 | int8_t _cs, _irq; 40 | uint8_t _sing_reg_read(uint8_t RegAdd); 41 | void _sing_reg_write(uint8_t RegAdd, uint8_t DataMask, uint8_t RegData); 42 | void _CalRCO(void); 43 | }; 44 | 45 | #endif 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /PWFusion_AS3935_I2C.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * File Name: PWFusion_AS3935_I2C.h 3 | * Processor/Platform: Arduino Uno R3 (tested) 4 | * Development Environment: Arduino 1.0.5 5 | * 6 | * Designed for use with with Playing With Fusion AS3935 Lightning Sensor 7 | * Breakout: SEN-39001-R01. 8 | * 9 | * SEN-39001 (universal applications) 10 | * ---> http://www.playingwithfusion.com/productview.php?pdid=22 11 | * 12 | * Copyright © 2015 Playing With Fusion, Inc. 13 | * SOFTWARE LICENSE AGREEMENT: This code is released under the MIT License. 14 | * 15 | * Permission is hereby granted, free of charge, to any person obtaining a 16 | * copy of this software and associated documentation files (the "Software"), 17 | * to deal in the Software without restriction, including without limitation 18 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 19 | * and/or sell copies of the Software, and to permit persons to whom the 20 | * Software is furnished to do so, subject to the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be included in 23 | * all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 30 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 31 | * DEALINGS IN THE SOFTWARE. 32 | * ************************************************************************** 33 | * REVISION HISTORY: 34 | * Author Date Comments 35 | * J. Steinlage 2015Jul20 Original version 36 | * J. Steinlage 2016Jul05 Fixed data write issue - now writing 'NewRegData' 37 | * based on feedback from J Shuhy and A Jahnke 38 | * 39 | * Playing With Fusion, Inc. invests time and resources developing open-source 40 | * code. Please support Playing With Fusion and continued open-source 41 | * development by buying products from Playing With Fusion! 42 | * 43 | * ************************************************************************** 44 | * ADDITIONAL NOTES: 45 | * This file contains functions to interface with the AS3935 Franklin 46 | * Lightning Sensor manufactured by AMS. Originally designed for application 47 | * on the Arduino Uno platform. 48 | **************************************************************************/ 49 | #include "PWFusion_AS3935_I2C.h" 50 | 51 | PWF_AS3935_I2C::PWF_AS3935_I2C(uint8_t DEVADDx, uint8_t IRQx) 52 | { 53 | _devadd = DEVADDx; 54 | _irq = IRQx; 55 | 56 | // initalize the chip select pins 57 | pinMode(_irq, INPUT); 58 | } 59 | 60 | uint8_t PWF_AS3935_I2C::_sing_reg_read(uint8_t RegAdd) 61 | { 62 | // I2C address Register address num bytes 63 | I2c.read((uint8_t)_devadd, (uint8_t)RegAdd, (uint8_t)0x01); // Use I2C library to read register 64 | uint8_t RegData = I2c.receive(); // receive the I2C data 65 | return RegData; 66 | } 67 | 68 | void PWF_AS3935_I2C::_sing_reg_write(uint8_t RegAdd, uint8_t DataMask, uint8_t RegData) 69 | { 70 | // start by reading original register data (only modifying what we need to) 71 | uint8_t OrigRegData = _sing_reg_read(RegAdd); 72 | 73 | // calculate new register data... 'delete' old targeted data, replace with new data 74 | // note: 'DataMask' must be bits targeted for replacement 75 | // add'l note: this function does NOT shift values into the proper place... they need to be there already 76 | uint8_t NewRegData = ((OrigRegData & ~DataMask) | (RegData & DataMask)); 77 | 78 | // finally, write the data to the register 79 | I2c.write(_devadd, RegAdd, NewRegData); 80 | Serial.print("wrt: "); 81 | Serial.print(NewRegData,HEX); 82 | Serial.print(" Act: "); 83 | Serial.println(_sing_reg_read(RegAdd),HEX); 84 | } 85 | 86 | void PWF_AS3935_I2C::AS3935_Reset() 87 | { 88 | _AS3935_Reset(); // reset registers to default 89 | } 90 | 91 | void PWF_AS3935_I2C::_AS3935_Reset() 92 | { 93 | // run PRESET_DEFAULT Direct Command to set all registers in default state 94 | I2c.write(_devadd, (uint8_t)0x3C, (uint8_t)0x96); 95 | delay(2); // wait 2ms to complete 96 | } 97 | 98 | void PWF_AS3935_I2C::_CalRCO() 99 | { 100 | // run ALIB_RCO Direct Command to cal internal RCO 101 | I2c.write(_devadd, (uint8_t)0x3D, (uint8_t)0x96); 102 | delay(2); // wait 2ms to complete 103 | } 104 | 105 | void PWF_AS3935_I2C::AS3935_PowerUp(void) 106 | { 107 | // power-up sequence based on datasheet, pg 23/27 108 | // register 0x00, PWD bit: 0 (clears PWD) 109 | _sing_reg_write(0x00, 0x01, 0x00); 110 | _CalRCO(); // run RCO cal cmd 111 | _sing_reg_write(0x08, 0x20, 0x20); // set DISP_SRCO to 1 112 | delay(2); 113 | _sing_reg_write(0x08, 0x20, 0x00); // set DISP_SRCO to 0 114 | } 115 | 116 | void PWF_AS3935_I2C::AS3935_PowerDown(void) 117 | { 118 | // register 0x00, PWD bit: 0 (sets PWD) 119 | _sing_reg_write(0x00, 0x01, 0x01); 120 | Serial.println("AS3935 powered down"); 121 | } 122 | 123 | void PWF_AS3935_I2C::AS3935_DisturberEn(void) 124 | { 125 | // register 0x03, PWD bit: 5 (sets MASK_DIST) 126 | _sing_reg_write(0x03, 0x20, 0x00); 127 | Serial.println("disturber detection enabled"); 128 | } 129 | 130 | void PWF_AS3935_I2C::AS3935_DisturberDis(void) 131 | { 132 | // register 0x03, PWD bit: 5 (sets MASK_DIST) 133 | _sing_reg_write(0x03, 0x20, 0x20); 134 | } 135 | 136 | void PWF_AS3935_I2C::AS3935_SetIRQ_Output_Source(uint8_t irq_select) 137 | { 138 | // set interrupt source - what to displlay on IRQ pin 139 | // reg 0x08, bits 5 (TRCO), 6 (SRCO), 7 (LCO) 140 | // only one should be set at once, I think 141 | // 0 = NONE, 1 = TRCO, 2 = SRCO, 3 = LCO 142 | 143 | if(1 == irq_select) 144 | { 145 | _sing_reg_write(0x08, 0xE0, 0x20); // set only TRCO bit 146 | } 147 | else if(2 == irq_select) 148 | { 149 | _sing_reg_write(0x08, 0xE0, 0x40); // set only SRCO bit 150 | } 151 | else if(3 == irq_select) 152 | { 153 | _sing_reg_write(0x08, 0xE0, 0x80); // set only LCO bit 154 | } 155 | else // assume 0 156 | { 157 | _sing_reg_write(0x08, 0xE0, 0x00); // clear IRQ pin display bits 158 | } 159 | 160 | } 161 | 162 | void PWF_AS3935_I2C::AS3935_SetTuningCaps(uint8_t cap_val) 163 | { 164 | // Assume only numbers divisible by 8 (because that's all the chip supports) 165 | if(120 < cap_val) // cap_value out of range, assume highest capacitance 166 | { 167 | _sing_reg_write(0x08, 0x0F, 0x0F); // set capacitance bits to maximum 168 | } 169 | else 170 | { 171 | _sing_reg_write(0x08, 0x0F, (cap_val>>3)); // set capacitance bits 172 | } 173 | Serial.print("capacitance set to 8x"); 174 | Serial.println((_sing_reg_read(0x08) & 0x0F)); 175 | } 176 | 177 | uint8_t PWF_AS3935_I2C::AS3935_GetInterruptSrc(void) 178 | { 179 | // definition of interrupt data on table 18 of datasheet 180 | // for this function: 181 | // 0 = unknown src, 1 = lightning detected, 2 = disturber, 3 = Noise level too high 182 | delay(10); // wait 3ms before reading (min 2ms per pg 22 of datasheet) 183 | uint8_t int_src = (_sing_reg_read(0x03) & 0x0F); // read register, get rid of non-interrupt data 184 | if(0x08 == int_src) 185 | { 186 | return 1; // lightning caused interrupt 187 | } 188 | else if(0x04 == int_src) 189 | { 190 | return 2; // disturber detected 191 | } 192 | else if(0x01 == int_src) 193 | { 194 | return 3; // Noise level too high 195 | } 196 | else{return 0;} // interrupt result not expected 197 | 198 | } 199 | 200 | uint8_t PWF_AS3935_I2C::AS3935_GetLightningDistKm(void) 201 | { 202 | uint8_t strike_dist = (_sing_reg_read(0x07) & 0x3F); // read register, get rid of non-distance data 203 | return strike_dist; 204 | } 205 | 206 | uint32_t PWF_AS3935_I2C::AS3935_GetStrikeEnergyRaw(void) 207 | { 208 | uint32_t nrgy_raw = ((_sing_reg_read(0x06) & 0x1F) << 8); // MMSB, shift 8 bits left, make room for MSB 209 | nrgy_raw |= _sing_reg_read(0x05); // read MSB 210 | nrgy_raw <<= 8; // shift 8 bits left, make room for LSB 211 | nrgy_raw |= _sing_reg_read(0x04); // read LSB, add to others 212 | 213 | return nrgy_raw; 214 | } 215 | 216 | uint8_t PWF_AS3935_I2C::AS3935_SetMinStrikes(uint8_t min_strk) 217 | { 218 | // This function sets min strikes to the closest available number, rounding to the floor, 219 | // where necessary, then returns the physical value that was set. Options are 1, 5, 9 or 16 strikes. 220 | // see pg 22 of the datasheet for more info (#strikes in 17 min) 221 | if(5 > min_strk) 222 | { 223 | _sing_reg_write(0x02, 0x30, 0x00); 224 | return 1; 225 | } 226 | else if(9 > min_strk) 227 | { 228 | _sing_reg_write(0x02, 0x30, 0x10); 229 | return 5; 230 | } 231 | else if(16 > min_strk) 232 | { 233 | _sing_reg_write(0x02, 0x30, 0x20); 234 | return 9; 235 | } 236 | else 237 | { 238 | _sing_reg_write(0x02, 0x30, 0x30); 239 | return 16; 240 | } 241 | } 242 | 243 | void PWF_AS3935_I2C::AS3935_SetIndoors(void) 244 | { 245 | // AFE settings addres 0x00, bits 5:1 (10010, based on datasheet, pg 19, table 15) 246 | // this is the default setting at power-up (AS3935 datasheet, table 9) 247 | _sing_reg_write(0x00, 0x3E, 0x24); 248 | Serial.println("set up for indoor operation"); 249 | } 250 | 251 | void PWF_AS3935_I2C::AS3935_SetOutdoors(void) 252 | { 253 | // AFE settings addres 0x00, bits 5:1 (01110, based on datasheet, pg 19, table 15) 254 | _sing_reg_write(0x00, 0x3E, 0x1C); 255 | Serial.println("set up for outdoor operation"); 256 | } 257 | 258 | void PWF_AS3935_I2C::AS3935_ClearStatistics(void) 259 | { 260 | // clear is accomplished by toggling CL_STAT bit 'high-low-high' (then set low to move on) 261 | _sing_reg_write(0x02, 0x40, 0x40); // high 262 | _sing_reg_write(0x02, 0x40, 0x00); // low 263 | _sing_reg_write(0x02, 0x40, 0x40); // high 264 | } 265 | 266 | uint8_t PWF_AS3935_I2C::AS3935_GetNoiseFloorLvl(void) 267 | { 268 | // NF settings addres 0x01, bits 6:4 269 | // default setting of 010 at startup (datasheet, table 9) 270 | uint8_t reg_raw = _sing_reg_read(0x01); // read register 0x01 271 | return ((reg_raw & 0x70)>>4); // should return value from 0-7, see table 16 for info 272 | } 273 | 274 | void PWF_AS3935_I2C::AS3935_SetNoiseFloorLvl(uint8_t nf_sel) 275 | { 276 | // NF settings addres 0x01, bits 6:4 277 | // default setting of 010 at startup (datasheet, table 9) 278 | if(7 >= nf_sel) // nf_sel within expected range 279 | { 280 | _sing_reg_write(0x01, 0x70, ((nf_sel & 0x07)<<4)); 281 | } 282 | else 283 | { // out of range, set to default (power-up value 010) 284 | _sing_reg_write(0x01, 0x70, 0x20); 285 | } 286 | } 287 | 288 | uint8_t PWF_AS3935_I2C::AS3935_GetWatchdogThreshold(void) 289 | { 290 | // This function is used to read WDTH. It is used to increase robustness to disturbers, 291 | // though will make detection less efficient (see page 19, Fig 20 of datasheet) 292 | // WDTH register: add 0x01, bits 3:0 293 | // default value of 0001 294 | // values should only be between 0x00 and 0x0F (0 and 7) 295 | uint8_t reg_raw = _sing_reg_read(0x01); 296 | return (reg_raw & 0x0F); 297 | } 298 | 299 | void PWF_AS3935_I2C::AS3935_SetWatchdogThreshold(uint8_t wdth) 300 | { 301 | // This function is used to modify WDTH. It is used to increase robustness to disturbers, 302 | // though will make detection less efficient (see page 19, Fig 20 of datasheet) 303 | // WDTH register: add 0x01, bits 3:0 304 | // default value of 0001 305 | // values should only be between 0x00 and 0x0F (0 and 7) 306 | _sing_reg_write(0x01, 0x0F, (wdth & 0x0F)); 307 | } 308 | 309 | uint8_t PWF_AS3935_I2C::AS3935_GetSpikeRejection(void) 310 | { 311 | // This function is used to read SREJ (spike rejection). Similar to the Watchdog threshold, 312 | // it is used to make the system more robust to disturbers, though will make general detection 313 | // less efficient (see page 20-21, especially Fig 21 of datasheet) 314 | // SREJ register: add 0x02, bits 3:0 315 | // default value of 0010 316 | // values should only be between 0x00 and 0x0F (0 and 7) 317 | uint8_t reg_raw = _sing_reg_read(0x02); 318 | return (reg_raw & 0x0F); 319 | } 320 | 321 | void PWF_AS3935_I2C::AS3935_SetSpikeRejection(uint8_t srej) 322 | { 323 | // This function is used to modify SREJ (spike rejection). Similar to the Watchdog threshold, 324 | // it is used to make the system more robust to disturbers, though will make general detection 325 | // less efficient (see page 20-21, especially Fig 21 of datasheet) 326 | // WDTH register: add 0x02, bits 3:0 327 | // default value of 0010 328 | // values should only be between 0x00 and 0x0F (0 and 7) 329 | _sing_reg_write(0x02, 0x0F, (srej & 0x0F)); 330 | } 331 | 332 | void PWF_AS3935_I2C::AS3935_SetLCO_FDIV(uint8_t fdiv) 333 | { 334 | // This function sets LCO_FDIV register. This is useful in the tuning of the antenna 335 | // LCO_FDIV register: add 0x03, bits 7:6 336 | // default value: 00 337 | // set 0, 1, 2 or 3 for ratios of 16, 32, 64 and 128, respectively. 338 | // See pg 23, Table 20 for more info. 339 | _sing_reg_write(0x03, 0xC0, ((fdiv & 0x03) << 5)); 340 | } 341 | 342 | void PWF_AS3935_I2C::AS3935_PrintAllRegs(void) 343 | { 344 | Serial.print("Reg 0x00: "); 345 | Serial.println(_sing_reg_read(0x00)); 346 | Serial.print("Reg 0x01: "); 347 | Serial.println(_sing_reg_read(0x01)); 348 | Serial.print("Reg 0x02: "); 349 | Serial.println(_sing_reg_read(0x02)); 350 | Serial.print("Reg 0x03: "); 351 | Serial.println(_sing_reg_read(0x03)); 352 | Serial.print("Reg 0x04: "); 353 | Serial.println(_sing_reg_read(0x04)); 354 | Serial.print("Reg 0x05: "); 355 | Serial.println(_sing_reg_read(0x05)); 356 | Serial.print("Reg 0x06: "); 357 | Serial.println(_sing_reg_read(0x06)); 358 | Serial.print("Reg 0x07: "); 359 | Serial.println(_sing_reg_read(0x07)); 360 | Serial.print("Reg 0x08: "); 361 | Serial.println(_sing_reg_read(0x08)); 362 | uint32_t nrgy_val = AS3935_GetStrikeEnergyRaw(); 363 | Serial.println(nrgy_val); 364 | } 365 | 366 | void PWF_AS3935_I2C::AS3935_ManualCal(uint8_t capacitance, uint8_t location, uint8_t disturber) 367 | { 368 | // start by powering up 369 | AS3935_PowerUp(); 370 | 371 | // indoors/outdoors next... 372 | if(1 == location) // set outdoors if 1 373 | { 374 | AS3935_SetOutdoors(); 375 | } 376 | else // set indoors if anything but 1 377 | { 378 | AS3935_SetIndoors(); 379 | } 380 | 381 | // disturber cal 382 | if(0 == disturber) // disabled if 0 383 | { 384 | AS3935_DisturberDis(); 385 | } 386 | else // enabled if anything but 0 387 | { 388 | AS3935_DisturberEn(); 389 | } 390 | 391 | AS3935_SetIRQ_Output_Source(0); 392 | 393 | delay(500); 394 | // capacitance first... directly write value here 395 | AS3935_SetTuningCaps(capacitance); 396 | 397 | Serial.println("AS3935 manual cal complete"); 398 | } 399 | // a nice function would be to read the last 'x' strike data values.... 400 | 401 | -------------------------------------------------------------------------------- /PWFusion_AS3935_I2C.h: -------------------------------------------------------------------------------- 1 | #ifndef PWF_AS3935_I2C_h 2 | #define PWF_AS3935_I2C_h 3 | 4 | #include "Arduino.h" 5 | #include "avr/pgmspace.h" 6 | #include "util/delay.h" 7 | #include "stdlib.h" 8 | #include "I2C.h" 9 | 10 | class PWF_AS3935_I2C 11 | { 12 | public: 13 | PWF_AS3935_I2C(uint8_t DEVADDx, uint8_t IRQx); 14 | void AS3935_ManualCal(uint8_t capacitance, uint8_t location, uint8_t disturber); 15 | void AS3935_Reset(void); 16 | void AS3935_PowerUp(void); 17 | void AS3935_PowerDown(void); 18 | void AS3935_DisturberEn(void); 19 | void AS3935_DisturberDis(void); 20 | void AS3935_SetIRQ_Output_Source(uint8_t irq_select); 21 | void AS3935_SetTuningCaps(uint8_t cap_val); 22 | uint8_t AS3935_GetInterruptSrc(void); 23 | uint8_t AS3935_GetLightningDistKm(void); 24 | uint32_t AS3935_GetStrikeEnergyRaw(void); 25 | uint8_t AS3935_SetMinStrikes(uint8_t min_strk); 26 | void AS3935_ClearStatistics(void); 27 | void AS3935_SetIndoors(void); 28 | void AS3935_SetOutdoors(void); 29 | uint8_t AS3935_GetNoiseFloorLvl(void); 30 | void AS3935_SetNoiseFloorLvl(uint8_t nf_sel); 31 | uint8_t AS3935_GetWatchdogThreshold(void); 32 | void AS3935_SetWatchdogThreshold(uint8_t wdth); 33 | uint8_t AS3935_GetSpikeRejection(void); 34 | void AS3935_SetSpikeRejection(uint8_t srej); 35 | void AS3935_SetLCO_FDIV(uint8_t fdiv); 36 | void AS3935_PrintAllRegs(void); 37 | 38 | private: 39 | uint8_t _irq, _devadd; 40 | uint8_t _sing_reg_read(uint8_t RegAdd); 41 | void _sing_reg_write(uint8_t RegAdd, uint8_t DataMask, uint8_t RegData); 42 | void _AS3935_Reset(void); 43 | void _CalRCO(void); 44 | }; 45 | 46 | #endif 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Selbstbau-868MHz-Funk-Wetterstation (mit Netzteilbetrieb) für HomeMatic [![Build Status](https://travis-ci.org/jp112sdl/HB-UNI-Sen-WEA.svg?branch=master)](https://travis-ci.org/jp112sdl/HB-UNI-Sen-WEA) [![License: CC BY-NC-SA 4.0](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) 2 | 3 | ### Die Dokumentation zu diesem Projekt findet ihr im -> [Wiki](https://github.com/jp112sdl/HB-UNI-Sen-WEA/wiki). 4 | 5 | **Hinweise:** 6 | - **die aktuelle Version des Source-Codes setzt mind. [Addon Version V1.20](https://github.com/jp112sdl/HB-UNI-Sen-WEA/wiki/Addon) oder höher voraus!** 7 | - **vor dem Flashen des Codes immer auf die neueste AskSinPP(-master) Bibliothek aktualisieren** 8 | 9 | Besten Dank an [Christoph Herrmann](https://www.facebook.com/hermi.leipzig) für die Zusendung seines Nachbaus ([Thingiverse-Link](https://www.thingiverse.com/thing:3173141)): 10 | ![complete](Images/sample1_1.jpg) 11 |
12 | Hier meine Version unter Verwendung eines Huger Regenmengenmessers und noch vor der Installation des Regendetektors: 13 | ![complete_jp](Images/4.png) 14 | -------------------------------------------------------------------------------- /RaindetectorStallBizTest/RaindetectorStallBizTest.ino: -------------------------------------------------------------------------------- 1 | #define RAINDETECTOR_CRG_PIN 4 // D4 2 | #define RAINDETECTOR_DISCRG_PIN A3 // A3 3 | #define RAINDETECTOR_HEATING_PIN 9 // D9 4 | 5 | void setup() { 6 | Serial.begin(57600); 7 | Serial.println("Raindetector Test"); 8 | digitalWrite(RAINDETECTOR_HEATING_PIN, LOW); 9 | pinMode(RAINDETECTOR_HEATING_PIN, OUTPUT); 10 | pinMode(RAINDETECTOR_CRG_PIN, OUTPUT); 11 | pinMode(RAINDETECTOR_DISCRG_PIN, INPUT); 12 | } 13 | 14 | void loop() { 15 | static unsigned int count = 0; 16 | 17 | if ((++count % 10) == 0) { 18 | /* toggle heating every 10 cycles */ 19 | if (digitalRead(RAINDETECTOR_HEATING_PIN) == LOW) { 20 | digitalWrite(RAINDETECTOR_HEATING_PIN, HIGH); 21 | Serial.println("Heating switched on!"); 22 | } else { 23 | digitalWrite(RAINDETECTOR_HEATING_PIN, LOW); 24 | Serial.println("Heating switched off!"); 25 | } 26 | } 27 | 28 | digitalWrite(RAINDETECTOR_CRG_PIN, HIGH); 29 | _delay_ms(2); 30 | digitalWrite(RAINDETECTOR_CRG_PIN, LOW); 31 | int rdVal = analogRead(RAINDETECTOR_DISCRG_PIN); 32 | Serial.println("Raindetector: " + String(rdVal)); 33 | delay(1000); 34 | } 35 | -------------------------------------------------------------------------------- /Renkforce_WindVane/2016-11-12-21.50.05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/Renkforce_WindVane/2016-11-12-21.50.05.jpg -------------------------------------------------------------------------------- /Renkforce_WindVane/Renkforce_WindVane.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #define PWM_OUT_PIN PB4 3 | 4 | SoftwareSerial wvSerial(PB3, PB5); // RX, TX 5 | 6 | #define START_BYTE 0x2c 7 | 8 | //uint8_t directionBytes1[4] = {0x24, 0x64, 0x2c, 0x6c }; 9 | //uint8_t directionBytes2[4] = {0x04, 0x0c, 0x01, 0x07 }; 10 | 11 | uint8_t directionBytes1[4] = {0x26, 0x66, 0x2e, 0x6e }; 12 | uint8_t directionBytes2[4] = {0x06, 0x0e, 0x01, 0x07 }; 13 | 14 | uint8_t receivedValues [4]; 15 | uint8_t idx = 0; 16 | uint8_t pwmOutputValue = 0; 17 | uint8_t lastPwmOutputValue = 0; 18 | 19 | void setup() { 20 | wvSerial.begin(2400); 21 | //wvSerial.print("HELLO"); 22 | pinMode(PWM_OUT_PIN, OUTPUT); 23 | } 24 | 25 | void loop() { 26 | if (wvSerial.available()) { 27 | uint8_t recv = wvSerial.read(); 28 | if ((recv >> 2) == START_BYTE) idx = 0; 29 | receivedValues[idx] = recv; 30 | //wvSerial.print(receivedValues[idx], HEX); 31 | //wvSerial.print(" : "); 32 | idx++; 33 | if (idx > 2) { 34 | idx = 0; 35 | //wvSerial.println(""); 36 | } 37 | } else { 38 | if ((receivedValues[0] >> 2) == START_BYTE) { 39 | if ((receivedValues[1] == directionBytes1[0]) && (receivedValues[2] == directionBytes2[0])) pwmOutputValue = 0; // N 40 | if ((receivedValues[1] == directionBytes1[0]) && (receivedValues[2] == directionBytes2[1])) pwmOutputValue = 15; // NNO 41 | if ((receivedValues[1] == directionBytes1[0]) && (receivedValues[2] == directionBytes2[2])) pwmOutputValue = 30; // NO 42 | if ((receivedValues[1] == directionBytes1[0]) && (receivedValues[2] == directionBytes2[3])) pwmOutputValue = 45; // ONO 43 | 44 | if ((receivedValues[1] == directionBytes1[1]) && (receivedValues[2] == directionBytes2[0])) pwmOutputValue = 60; // O 45 | if ((receivedValues[1] == directionBytes1[1]) && (receivedValues[2] == directionBytes2[1])) pwmOutputValue = 75; // OSO 46 | if ((receivedValues[1] == directionBytes1[1]) && (receivedValues[2] == directionBytes2[2])) pwmOutputValue = 90; // SO 47 | if ((receivedValues[1] == directionBytes1[1]) && (receivedValues[2] == directionBytes2[3])) pwmOutputValue = 105; // SSO 48 | 49 | if ((receivedValues[1] == directionBytes1[2]) && (receivedValues[2] == directionBytes2[0])) pwmOutputValue = 120; // S 50 | if ((receivedValues[1] == directionBytes1[2]) && (receivedValues[2] == directionBytes2[1])) pwmOutputValue = 135; // SSW 51 | if ((receivedValues[1] == directionBytes1[2]) && (receivedValues[2] == directionBytes2[2])) pwmOutputValue = 150; // SW 52 | if ((receivedValues[1] == directionBytes1[2]) && (receivedValues[2] == directionBytes2[3])) pwmOutputValue = 165; // WSW 53 | 54 | if ((receivedValues[1] == directionBytes1[3]) && (receivedValues[2] == directionBytes2[0])) pwmOutputValue = 180; // W 55 | if ((receivedValues[1] == directionBytes1[3]) && (receivedValues[2] == directionBytes2[1])) pwmOutputValue = 195; // WNW 56 | if ((receivedValues[1] == directionBytes1[3]) && (receivedValues[2] == directionBytes2[2])) pwmOutputValue = 210; // NW 57 | if ((receivedValues[1] == directionBytes1[3]) && (receivedValues[2] == directionBytes2[3])) pwmOutputValue = 225; // NNW 58 | 59 | if (pwmOutputValue != lastPwmOutputValue) { 60 | analogWrite(PWM_OUT_PIN, pwmOutputValue); 61 | lastPwmOutputValue = pwmOutputValue; 62 | //wvSerial.println("pwmOutputValue = " + String(pwmOutputValue)); 63 | } 64 | } 65 | idx = 0; 66 | } 67 | delay(100); 68 | } 69 | -------------------------------------------------------------------------------- /Sensors/PCF8574_WindDir.h: -------------------------------------------------------------------------------- 1 | #ifndef PCF8574_WindDir_h 2 | #define PCF8574_WindDir_h 3 | 4 | //https://github.com/xreef/PCF8574_library 5 | #include 6 | 7 | namespace as { 8 | 9 | template 10 | class PCF8574_WindDir { 11 | private: 12 | PCF8574 pcf8574; 13 | public: 14 | PCF8574_WindDir () : pcf8574(ADDRESS) {} 15 | 16 | void init () { 17 | for (uint8_t i = 0; i < 8; i++) 18 | pcf8574.pinMode(i, INPUT); 19 | 20 | pcf8574.begin(); 21 | 22 | } 23 | 24 | uint8_t winddirValue(bool asIndex = false) { 25 | if (pcf8574.digitalRead(P0) == 0) return asIndex ? 0 : 0; 26 | if (pcf8574.digitalRead(P1) == 0) return asIndex ? 1 : 15; 27 | if (pcf8574.digitalRead(P2) == 0) return asIndex ? 2 : 30; 28 | if (pcf8574.digitalRead(P3) == 0) return asIndex ? 3 : 45; 29 | if (pcf8574.digitalRead(P4) == 0) return asIndex ? 4 : 60; 30 | if (pcf8574.digitalRead(P5) == 0) return asIndex ? 5 : 75; 31 | if (pcf8574.digitalRead(P6) == 0) return asIndex ? 6 : 90; 32 | if (pcf8574.digitalRead(P7) == 0) return asIndex ? 7 : 105; 33 | return 0; 34 | } 35 | 36 | }; 37 | 38 | } 39 | #endif 40 | -------------------------------------------------------------------------------- /Sensors/Sens_As3935.h: -------------------------------------------------------------------------------- 1 | //- ----------------------------------------------------------------------------------------------------------------------- 2 | // AskSin++ 3 | // 2018-06-28 jp112sdl Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ 4 | //- ----------------------------------------------------------------------------------------------------------------------- 5 | 6 | #ifndef __SENSORS_AS3935_h__ 7 | #define __SENSORS_AS3935_h__ 8 | 9 | // #define AS3935_USE_I2C // if not defined, SPI is used 10 | 11 | #define EI_NOTEXTERNAL 12 | #include 13 | 14 | #include 15 | 16 | #ifdef AS3935_USE_I2C 17 | #include "../PWFusion_AS3935_I2C.h" 18 | #else 19 | #include 20 | #include "../PWFusion_AS3935.h" 21 | #endif 22 | 23 | volatile uint8_t _lightning_isr_counter = 0; 24 | 25 | namespace as { 26 | 27 | template 28 | class Sens_As3935 : public Sensor { 29 | #ifdef AS3935_USE_I2C 30 | ::PWF_AS3935_I2C _lightningDetector; 31 | #else 32 | ::PWF_AS3935 _lightningDetector; 33 | #endif 34 | uint8_t _interrupt_src; 35 | public: 36 | Sens_As3935 () : _lightningDetector(_AS3935_CS_PIN_OR_ADDR, _AS3935_IRQ_PIN), _interrupt_src(0) {} 37 | enum _AS3935_ENVIRONMENT { 38 | AS3935_ENVIRONMENT_OUTDOOR, 39 | AS3935_ENVIRONMENT_INDOOR 40 | }; 41 | 42 | void init (uint8_t _AS3935_CAPACITANCE, uint8_t _AS3935_DIST_EN, uint8_t _AS3935_ENVIRONMENT, uint8_t _AS3935_MINSTRIKES, uint8_t _AS3935_WATCHDOGTHRESHOLD, uint8_t _AS3935_NOISEFLOORLEVEL, uint8_t _AS3935_SPIKEREJECTION) { 43 | if ( digitalPinToInterrupt(_AS3935_IRQ_PIN) == NOT_AN_INTERRUPT ) enableInterrupt(_AS3935_IRQ_PIN, lightningISR, RISING); else attachInterrupt(digitalPinToInterrupt(_AS3935_IRQ_PIN), lightningISR, RISING); 44 | 45 | #ifdef AS3935_USE_I2C 46 | I2c.begin(); 47 | I2c.pullup(true); 48 | I2c.setSpeed(1); 49 | #endif 50 | 51 | _lightningDetector.AS3935_Reset(); 52 | _lightningDetector.AS3935_ManualCal(_AS3935_CAPACITANCE, _AS3935_DIST_EN, _AS3935_ENVIRONMENT); 53 | _lightningDetector.AS3935_SetMinStrikes(_AS3935_MINSTRIKES); 54 | _lightningDetector.AS3935_SetSpikeRejection(_AS3935_SPIKEREJECTION); 55 | _lightningDetector.AS3935_SetWatchdogThreshold(_AS3935_WATCHDOGTHRESHOLD); 56 | _lightningDetector.AS3935_SetNoiseFloorLvl(_AS3935_NOISEFLOORLEVEL); 57 | _lightningDetector.AS3935_PrintAllRegs(); 58 | DPRINTLN("AS3935 Init done."); 59 | _present = true; 60 | } 61 | 62 | static void lightningISR() { 63 | _lightning_isr_counter = 1; 64 | } 65 | 66 | uint8_t GetInterruptSrc (__attribute__((unused)) bool async=false) { 67 | return ( present() == true ) ? _lightningDetector.AS3935_GetInterruptSrc() : 255; 68 | } 69 | 70 | uint8_t LightningDistKm (__attribute__((unused)) bool async=false) { 71 | return (present() == true) ? _lightningDetector.AS3935_GetLightningDistKm() : 255; 72 | } 73 | 74 | void PrintAllRegs() { 75 | _lightningDetector.AS3935_PrintAllRegs(); 76 | } 77 | 78 | uint8_t LightningIsrCounter() { return _lightning_isr_counter; } 79 | bool ResetLightninIsrCounter() { _lightning_isr_counter = 0; return true; } 80 | 81 | }; 82 | 83 | } 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /Sensors/Sens_As5600.h: -------------------------------------------------------------------------------- 1 | //- ----------------------------------------------------------------------------------------------------------------------- 2 | // AskSin++ 3 | // 2020-01-03 jp112sdl Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ 4 | //- ----------------------------------------------------------------------------------------------------------------------- 5 | 6 | #ifndef SENSORS_SENS_AS5600_H_ 7 | #define SENSORS_SENS_AS5600_H_ 8 | 9 | #include 10 | 11 | #define AS5600ADDRESS 0x36 12 | #define ZMCOADDRESS 0x00 13 | #define ZPOSADDRESSMSB 0x01 14 | #define ZPOSADDRESSLSB 0x02 15 | #define MPOSADDRESSMSB 0x03 16 | #define MPOSADDRESSLSB 0x04 17 | #define MANGADDRESSMSB 0x05 18 | #define MANGADDRESSLSB 0x06 19 | #define CONFADDRESSMSB 0x07 20 | #define CONFADDRESSLSB 0x08 21 | #define RAWANGLEADDRESSMSB 0x0C 22 | #define RAWANGLEADDRESSLSB 0x0D 23 | #define ANGLEADDRESSMSB 0x0E 24 | #define ANGLEADDRESSLSB 0x0F 25 | #define STATUSADDRESS 0x0B 26 | #define AGCADDRESS 0x1A 27 | #define MAGNITUDEADDRESSMSB 0x1B 28 | #define MAGNITUDEADDRESSLSB 0x1C 29 | #define BURNADDRESS 0xFF 30 | 31 | namespace as { 32 | 33 | class Sens_As5600 { 34 | private: 35 | int16_t _angle; 36 | bool _present; 37 | 38 | uint8_t _getReg(uint8_t reg) 39 | { 40 | Wire.beginTransmission(AS5600ADDRESS); 41 | Wire.write(reg); 42 | Wire.endTransmission(); 43 | 44 | Wire.requestFrom(AS5600ADDRESS, 1); 45 | 46 | uint8_t _msb = 0; 47 | if(Wire.available() <=1) { 48 | _msb = Wire.read(); 49 | } 50 | 51 | return _msb; 52 | } 53 | 54 | uint16_t _getRegs(uint8_t regMSB, uint8_t regLSB) 55 | { 56 | uint8_t _lsb = 0; 57 | uint8_t _msb = 0; 58 | 59 | Wire.beginTransmission(AS5600ADDRESS); 60 | Wire.write(regMSB); 61 | Wire.endTransmission(); 62 | delay(10); 63 | 64 | Wire.requestFrom(AS5600ADDRESS, 1); 65 | 66 | if(Wire.available() <=1) { 67 | _msb = Wire.read(); 68 | } 69 | 70 | Wire.requestFrom(AS5600ADDRESS, 1); 71 | 72 | Wire.beginTransmission(AS5600ADDRESS); 73 | Wire.write(regLSB); 74 | Wire.endTransmission(); 75 | 76 | if(Wire.available() <=1) { 77 | _lsb = Wire.read(); 78 | } 79 | 80 | return (_lsb) + (_msb & 0b00001111) * 256; 81 | } 82 | public: 83 | 84 | Sens_As5600 () : _angle(0), _present(false) {} 85 | 86 | void init () { 87 | Wire.begin(); 88 | 89 | uint8_t status = _getReg(STATUSADDRESS) & 0b00111000; 90 | if (status == 32) { 91 | _present=true; 92 | DPRINTLN(F("AS5600 OK.")); 93 | } else { 94 | DPRINTLN(F("AS5600 FAILURE.")); 95 | } 96 | } 97 | 98 | void measure () { 99 | if (_present) { 100 | uint16_t raw = _getRegs(RAWANGLEADDRESSMSB, RAWANGLEADDRESSLSB); 101 | _angle = map(raw, 0, 4096, 0, 359); 102 | } 103 | } 104 | 105 | int16_t angle () { return _angle; } 106 | }; 107 | 108 | } 109 | 110 | 111 | 112 | #endif /* SENSORS_SENS_AS5600_H_ */ 113 | -------------------------------------------------------------------------------- /Sensors/Sens_Bme280.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _SENS_BME280_H_ 3 | #define _SENS_BME280_H_ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace as { 11 | 12 | class Sens_Bme280 : public Sensor { 13 | 14 | int16_t _temperature; 15 | uint16_t _pressure; 16 | uint16_t _pressureNN; 17 | uint8_t _humidity; 18 | uint16_t _dewPoint; 19 | 20 | BME280I2C _bme280; // Default : forced mode, standby time = 1000 ms, Oversampling = pressure ×1, temperature ×1, humidity ×1, filter off 21 | 22 | public: 23 | 24 | Sens_Bme280 () : _temperature(0), _pressure(0), _pressureNN(0), _humidity(0), _dewPoint(0) {} 25 | 26 | void init () { 27 | 28 | Wire.begin(); //ToDo sync with further I2C sensor classes 29 | 30 | uint8_t i = 10; 31 | while( (!_bme280.begin()) && (i > 0) ) { 32 | delay(100); 33 | i--; 34 | } 35 | 36 | switch(_bme280.chipModel()) { 37 | case BME280::ChipModel_BME280: 38 | _present = true; 39 | DPRINTLN(F("BME280 sensor OK")); 40 | break; 41 | default: 42 | DPRINTLN(F("BME280 sensor NOT OK")); 43 | } 44 | } 45 | 46 | void measure (uint16_t height) { 47 | if (_present == true) { 48 | float temp(NAN), hum(NAN), pres(NAN); 49 | _bme280.read(pres, temp, hum, BME280::TempUnit_Celsius, BME280::PresUnit_hPa); 50 | 51 | _temperature = (int16_t)(temp * 10); 52 | _pressure = (uint16_t)(pres * 10); 53 | _pressureNN = (uint16_t)(EnvironmentCalculations::EquivalentSeaLevelPressure(float(height), temp, pres) * 10); 54 | _humidity = (uint8_t)hum; 55 | _dewPoint = (int16_t)(EnvironmentCalculations::DewPoint(temp, hum, EnvironmentCalculations::TempUnit_Celsius) * 10); 56 | 57 | DPRINTLN(F("BME280:")); 58 | DPRINT(F("-T : ")); DDECLN(_temperature); 59 | DPRINT(F("-P : ")); DDECLN(_pressure); 60 | DPRINT(F("-P(NN): ")); DDECLN(_pressureNN); 61 | DPRINT(F("-H : ")); DDECLN(_humidity); 62 | DPRINT(F("-DP : ")); DDECLN(_dewPoint); 63 | } 64 | } 65 | 66 | int16_t temperature () { return _temperature; } 67 | uint16_t pressure () { return _pressure; } 68 | uint16_t pressureNN () { return _pressureNN; } 69 | uint8_t humidity () { return _humidity; } 70 | int16_t dewPoint () { return _dewPoint; } 71 | }; 72 | 73 | } 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /Sensors/VentusW132.h: -------------------------------------------------------------------------------- 1 | #ifndef VentusW132_h 2 | #define VentusW132_h 3 | 4 | #define N_MASK 0b00001000 5 | #define NO_MASK 0b00001100 6 | #define O_MASK 0b00000100 7 | #define SO_MASK 0b00000110 8 | #define S_MASK 0b00000010 9 | #define SW_MASK 0b00000011 10 | #define W_MASK 0b00000001 11 | #define NW_MASK 0b00001001 12 | 13 | namespace as { 14 | 15 | template 16 | class VentusW132 { 17 | private: 18 | uint8_t pins[4]; 19 | public: 20 | VentusW132 () {} 21 | 22 | void init () { 23 | pins[0] = N_PIN; 24 | pins[1] = O_PIN; 25 | pins[2] = S_PIN; 26 | pins[3] = W_PIN; 27 | 28 | for (uint8_t i = 0; i < 4; i++) 29 | pinMode(pins[i], INPUT); 30 | 31 | } 32 | 33 | uint8_t readState() { 34 | uint8_t state = 0; 35 | for (uint8_t i = 0; i < 4; i++) { 36 | bool p = (pins[i] == A6 || pins[i] == A7) ? (analogRead(pins[i]) > 500) : digitalRead(pins[i]); 37 | state |= p << i; 38 | //DPRINT(F("read pin("));DDEC(pins[i]);DPRINT(") = ");DDECLN(p); 39 | } 40 | return state; 41 | } 42 | 43 | uint8_t winddirValue(bool asIndex = false) { 44 | uint8_t state = readState(); 45 | //DPRINT(F("state="));DHEXLN(state); 46 | 47 | if (state == N_MASK) return asIndex ? 0 : 0; 48 | if (state == NO_MASK) return asIndex ? 1 : 15; 49 | if (state == O_MASK) return asIndex ? 2 : 30; 50 | if (state == SO_MASK) return asIndex ? 3 : 45; 51 | if (state == S_MASK) return asIndex ? 4 : 60; 52 | if (state == SW_MASK) return asIndex ? 5 : 75; 53 | if (state == W_MASK) return asIndex ? 6 : 90; 54 | if (state == NW_MASK) return asIndex ? 7 : 105; 55 | return 0; 56 | } 57 | }; 58 | 59 | } 60 | #endif 61 | -------------------------------------------------------------------------------- /WinddirResistorTest/WinddirResistorTest.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const uint16_t WINDDIRS[] = { 58, 74, 52, 115, 97, 328, 302, 790, 559, 663, 187, 205, 163, 420, 129, 153 }; 4 | #define WINDDIRECTION_PIN A2 5 | #define WINDCOUNTER_PIN 5 6 | #define RAINQUANTITYCOUNTER_PIN 6 // Regenmengenmesser 7 | volatile int _windcounter = 0; 8 | int lastWindcounter = 0; 9 | int lastRaincounter = 0; 10 | volatile uint32_t _rainquantity_isr_counter = 0; 11 | 12 | void setup() { 13 | Serial.begin(57600); 14 | pinMode(WINDDIRECTION_PIN, INPUT_PULLUP); 15 | pinMode(RAINQUANTITYCOUNTER_PIN, INPUT_PULLUP); 16 | // put your setup code here, to run once: 17 | if ( digitalPinToInterrupt(WINDCOUNTER_PIN) == NOT_AN_INTERRUPT ) enableInterrupt(WINDCOUNTER_PIN, windcounterISR, RISING); else attachInterrupt(digitalPinToInterrupt(WINDCOUNTER_PIN), windcounterISR, RISING); 18 | if ( digitalPinToInterrupt(RAINQUANTITYCOUNTER_PIN) == NOT_AN_INTERRUPT ) enableInterrupt(RAINQUANTITYCOUNTER_PIN, rainquantitycounterISR, RISING); else attachInterrupt(digitalPinToInterrupt(RAINQUANTITYCOUNTER_PIN), rainquantitycounterISR, RISING); 19 | } 20 | 21 | void loop() { 22 | delay(100); 23 | int winddir = 0; // Grad/3: 60° = 20; 0° = Norden 24 | uint8_t idxwdir = 0; 25 | 26 | uint16_t aVal = 0; 27 | for (uint8_t i = 0; i <= 0xf; i++) { 28 | aVal += analogRead(WINDDIRECTION_PIN); 29 | } 30 | aVal = aVal >> 4; 31 | 32 | uint8_t WINDDIR_TOLERANCE = 2; 33 | if ((aVal > 100) && (aVal < 250)) WINDDIR_TOLERANCE = 5; 34 | if (aVal >= 250) WINDDIR_TOLERANCE = 10; 35 | 36 | for (uint8_t i = 0; i < sizeof(WINDDIRS) / sizeof(uint16_t); i++) { 37 | if (aVal < WINDDIRS[i] + WINDDIR_TOLERANCE && aVal > WINDDIRS[i] - WINDDIR_TOLERANCE) { 38 | idxwdir = i; 39 | winddir = (idxwdir * 15 + 2 / 2) / 2; 40 | break; 41 | } 42 | } 43 | Serial.println("A2 = " + String(aVal) + "; idx = " + String(idxwdir) + "; Tolerance = " + String(WINDDIR_TOLERANCE)); 44 | 45 | if (lastWindcounter != _windcounter) { 46 | lastWindcounter = _windcounter; 47 | Serial.println("windcounter = " + String(_windcounter)); 48 | } 49 | 50 | 51 | if (lastRaincounter != _rainquantity_isr_counter) { 52 | lastRaincounter = _rainquantity_isr_counter; 53 | Serial.println("raincounter = " + String(_rainquantity_isr_counter)); 54 | } 55 | 56 | } 57 | 58 | void windcounterISR() { 59 | _windcounter++; 60 | } 61 | 62 | void rainquantitycounterISR() { 63 | _rainquantity_isr_counter++; 64 | } 65 | -------------------------------------------------------------------------------- /ci/arduino-cli.yaml: -------------------------------------------------------------------------------- 1 | directories: 2 | data: .arduino15 3 | downloads: .arduino15/staging 4 | user: Arduino 5 | library: 6 | enable_unsafe_install: true 7 | logging: 8 | file: "" 9 | format: text 10 | level: warn 11 | metrics: 12 | addr: :9090 13 | enabled: false 14 | sketch: 15 | always_export_binaries: false 16 | -------------------------------------------------------------------------------- /ci/download-sketch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 3 | cd $DIR 4 | 5 | mkdir -p sketches 6 | cd sketches 7 | 8 | # Sketches from Git-Repositories 9 | GIT_REPOS=( 10 | "https://github.com/jp112sdl/HB-UNI-Sen-WEA.git" 11 | ) 12 | 13 | # Clone / update Repos in parallel 14 | for REPO_URL in ${GIT_REPOS[*]}; do 15 | REPO="$(basename $REPO_URL | cut -d. -f1)" 16 | if [ -e "$REPO" ] ; then 17 | echo "Pull changes from $REPO" 18 | (cd $REPO && git pull -q --depth 1) & 19 | else 20 | echo "Clone from $REPO" 21 | git clone -q --no-tags --depth 1 "$REPO_URL" & 22 | fi 23 | done 24 | wait 25 | -------------------------------------------------------------------------------- /ci/install-deps.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 3 | cd $DIR 4 | 5 | # Libs included in Lib-Manager 6 | LIBS=( 7 | "OneWire" 8 | ) 9 | 10 | # Libs from Git-Repositories 11 | GIT_LIBS=( 12 | "https://github.com/GreyGnome/EnableInterrupt" 13 | "https://github.com/rocketscream/Low-Power.git" 14 | "https://github.com/finitespace/BME280.git" 15 | "https://github.com/pa-pa/AskSinPP.git" 16 | ) 17 | 18 | # Install Libs 19 | arduino-cli lib install ${LIBS[*]} 20 | 21 | for REPO_URL in ${GIT_LIBS[*]}; do 22 | REPO="$(basename $REPO_URL | cut -d. -f1)" 23 | echo "Install $REPO from Git" 24 | ( arduino-cli lib install --git-url ${REPO_URL} 1>/dev/null )& 25 | done 26 | wait 27 | 28 | # Install Cores 29 | arduino-cli core update-index 30 | echo Install arduino:avr core 31 | arduino-cli core install arduino:avr@1.8.2 32 | -------------------------------------------------------------------------------- /ci/sen-wea.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 3 | cd $DIR 4 | SKETCHES=() 5 | 6 | SKETCHES+=(sketches/HB-UNI-Sen-WEA/HB-UNI-Sen-WEA.ino) 7 | 8 | # Run tests 9 | HAS_ERROR=false 10 | for FILE in "${SKETCHES[@]}"; do 11 | echo "Compiling $(basename $FILE)" 12 | arduino-cli compile \ 13 | --clean \ 14 | --quiet \ 15 | -b arduino:avr:pro:cpu=8MHzatmega328 \ 16 | $FILE 17 | [ $? -ne 0 ] && HAS_ERROR=true 18 | done 19 | 20 | # AES? 21 | # --build-property "build.extra_flags=-DUSE_AES -DHM_DEF_KEY=0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10 -DHM_DEF_KEY_INDEX=0" \ 22 | 23 | if $HAS_ERROR; then 24 | >&2 echo "Errors occurred!" 25 | exit 1 26 | fi -------------------------------------------------------------------------------- /docs/AS3935.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/docs/AS3935.pdf -------------------------------------------------------------------------------- /docs/AS5600.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/docs/AS5600.pdf -------------------------------------------------------------------------------- /docs/MAX44009.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/docs/MAX44009.pdf -------------------------------------------------------------------------------- /docs/VEML6070.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jp112sdl/HB-UNI-Sen-WEA/7e5923e6affa60dde26a8ff8b0b41b7839144021/docs/VEML6070.pdf --------------------------------------------------------------------------------