├── .gitignore ├── 4DSystems ├── 4D Workshop 4 IDE │ └── SysImages │ │ └── Buttons │ │ └── Slider01 │ │ ├── SmallGreen │ │ ├── 32x16 │ │ │ ├── Down.png │ │ │ ├── DownPressed.png │ │ │ ├── Up.png │ │ │ └── UpPressed.png │ │ ├── 48x24 │ │ │ ├── Down.png │ │ │ ├── DownPressed.png │ │ │ ├── Up.png │ │ │ └── UpPressed.png │ │ ├── 64x32 │ │ │ ├── Down.png │ │ │ ├── DownPressed.png │ │ │ ├── Up.png │ │ │ └── UpPressed.png │ │ └── Scaled │ │ │ ├── Down.png │ │ │ ├── DownPressed.png │ │ │ ├── Up.png │ │ │ └── UpPressed.png │ │ └── SmallRed │ │ ├── 32x16 │ │ ├── Down.png │ │ ├── DownPressed.png │ │ ├── Up.png │ │ └── UpPressed.png │ │ ├── 48x24 │ │ ├── Down.png │ │ ├── DownPressed.png │ │ ├── Up.png │ │ └── UpPressed.png │ │ ├── 64x32 │ │ ├── Down.png │ │ ├── DownPressed.png │ │ ├── Up.png │ │ └── UpPressed.png │ │ └── Scaled │ │ ├── Down.png │ │ ├── DownPressed.png │ │ ├── Up.png │ │ └── UpPressed.png └── AquariumController │ ├── AquariumController.4DGenie │ └── AquariumController.ImgData │ ├── KB1.kbd │ ├── KB2.kbd │ ├── KB3.kbd │ ├── Tahoma19____A.font │ ├── Tahoma19b___A.font │ └── WINPANEL-RED.bmp ├── Arduino └── AquariumController │ ├── AQUA_adc141s626.cpp │ ├── AQUA_adc141s626.h │ ├── AQUA_ads1115.cpp │ ├── AQUA_ads1115.h │ ├── AQUA_lcd.cpp │ ├── AQUA_lcd.h │ ├── AQUA_orp.cpp │ ├── AQUA_orp.h │ ├── AQUA_ph.cpp │ ├── AQUA_ph.h │ ├── AQUA_relay.cpp │ ├── AQUA_relay.h │ ├── AQUA_temp.cpp │ ├── AQUA_temp.h │ ├── AQUA_time.cpp │ ├── AQUA_time.h │ ├── AquariumController.h │ └── AquariumController.ino ├── Eagle └── Aqua_ph_orp │ ├── Aqua_ph_orp.brd │ ├── Aqua_ph_orp.sch │ └── Aqua_ph_orp.txt ├── LICENSE ├── Pics ├── VisiGenie.png ├── lcd1.jpg ├── lcd2.jpg ├── lcd3.jpg ├── lcd4.jpg ├── lcd5.jpg ├── lcd6.jpg ├── pH_orp_module.jpg ├── power1.jpg ├── power2.jpg └── power3.jpg ├── README.md └── Versions.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.bak 3 | *.idea 4 | *.project 5 | -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/32x16/Down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/32x16/Down.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/32x16/DownPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/32x16/DownPressed.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/32x16/Up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/32x16/Up.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/32x16/UpPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/32x16/UpPressed.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/48x24/Down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/48x24/Down.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/48x24/DownPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/48x24/DownPressed.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/48x24/Up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/48x24/Up.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/48x24/UpPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/48x24/UpPressed.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/64x32/Down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/64x32/Down.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/64x32/DownPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/64x32/DownPressed.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/64x32/Up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/64x32/Up.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/64x32/UpPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/64x32/UpPressed.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/Scaled/Down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/Scaled/Down.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/Scaled/DownPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/Scaled/DownPressed.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/Scaled/Up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/Scaled/Up.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/Scaled/UpPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallGreen/Scaled/UpPressed.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/32x16/Down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/32x16/Down.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/32x16/DownPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/32x16/DownPressed.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/32x16/Up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/32x16/Up.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/32x16/UpPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/32x16/UpPressed.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/48x24/Down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/48x24/Down.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/48x24/DownPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/48x24/DownPressed.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/48x24/Up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/48x24/Up.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/48x24/UpPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/48x24/UpPressed.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/64x32/Down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/64x32/Down.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/64x32/DownPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/64x32/DownPressed.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/64x32/Up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/64x32/Up.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/64x32/UpPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/64x32/UpPressed.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/Scaled/Down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/Scaled/Down.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/Scaled/DownPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/Scaled/DownPressed.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/Scaled/Up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/Scaled/Up.png -------------------------------------------------------------------------------- /4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/Scaled/UpPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/4D Workshop 4 IDE/SysImages/Buttons/Slider01/SmallRed/Scaled/UpPressed.png -------------------------------------------------------------------------------- /4DSystems/AquariumController/AquariumController.ImgData/KB1.kbd: -------------------------------------------------------------------------------- 1 | [Keys] 2 | Count=11 3 | 4 | [Key0] 5 | Caption=7 6 | ShiftCaption= 7 | KeyValue=-1 8 | ShiftKeyValue=-1 9 | SpecialKey=0 10 | Color=12632256 11 | ColorDown=8421504 12 | TextColor=0 13 | TextColorDown=0 14 | Width=30 15 | Height=30 16 | X=1 17 | Y=1 18 | ImageIndex=-1 19 | 20 | [Key1] 21 | Caption=8 22 | ShiftCaption= 23 | KeyValue=-1 24 | ShiftKeyValue=-1 25 | SpecialKey=0 26 | Color=12632256 27 | ColorDown=8421504 28 | TextColor=0 29 | TextColorDown=0 30 | Width=30 31 | Height=30 32 | X=31 33 | Y=1 34 | ImageIndex=-1 35 | 36 | [Key2] 37 | Caption=9 38 | ShiftCaption= 39 | KeyValue=-1 40 | ShiftKeyValue=-1 41 | SpecialKey=0 42 | Color=12632256 43 | ColorDown=8421504 44 | TextColor=0 45 | TextColorDown=0 46 | Width=30 47 | Height=30 48 | X=61 49 | Y=1 50 | ImageIndex=-1 51 | 52 | [Key3] 53 | Caption=4 54 | ShiftCaption= 55 | KeyValue=-1 56 | ShiftKeyValue=-1 57 | SpecialKey=0 58 | Color=12632256 59 | ColorDown=8421504 60 | TextColor=0 61 | TextColorDown=0 62 | Width=30 63 | Height=30 64 | X=1 65 | Y=31 66 | ImageIndex=-1 67 | 68 | [Key4] 69 | Caption=5 70 | ShiftCaption= 71 | KeyValue=-1 72 | ShiftKeyValue=-1 73 | SpecialKey=0 74 | Color=12632256 75 | ColorDown=8421504 76 | TextColor=0 77 | TextColorDown=0 78 | Width=30 79 | Height=30 80 | X=31 81 | Y=31 82 | ImageIndex=-1 83 | 84 | [Key5] 85 | Caption=6 86 | ShiftCaption= 87 | KeyValue=-1 88 | ShiftKeyValue=-1 89 | SpecialKey=0 90 | Color=12632256 91 | ColorDown=8421504 92 | TextColor=0 93 | TextColorDown=0 94 | Width=30 95 | Height=30 96 | X=61 97 | Y=31 98 | ImageIndex=-1 99 | 100 | [Key6] 101 | Caption=1 102 | ShiftCaption= 103 | KeyValue=-1 104 | ShiftKeyValue=-1 105 | SpecialKey=0 106 | Color=12632256 107 | ColorDown=8421504 108 | TextColor=0 109 | TextColorDown=0 110 | Width=30 111 | Height=30 112 | X=1 113 | Y=61 114 | ImageIndex=-1 115 | 116 | [Key7] 117 | Caption=2 118 | ShiftCaption= 119 | KeyValue=-1 120 | ShiftKeyValue=-1 121 | SpecialKey=0 122 | Color=12632256 123 | ColorDown=8421504 124 | TextColor=0 125 | TextColorDown=0 126 | Width=30 127 | Height=30 128 | X=31 129 | Y=61 130 | ImageIndex=-1 131 | 132 | [Key8] 133 | Caption=3 134 | ShiftCaption= 135 | KeyValue=-1 136 | ShiftKeyValue=-1 137 | SpecialKey=0 138 | Color=12632256 139 | ColorDown=8421504 140 | TextColor=0 141 | TextColorDown=0 142 | Width=30 143 | Height=30 144 | X=61 145 | Y=61 146 | ImageIndex=-1 147 | 148 | [Key9] 149 | Caption=0 150 | ShiftCaption= 151 | KeyValue=-1 152 | ShiftKeyValue=-1 153 | SpecialKey=0 154 | Color=12632256 155 | ColorDown=8421504 156 | TextColor=0 157 | TextColorDown=0 158 | Width=30 159 | Height=30 160 | X=1 161 | Y=91 162 | ImageIndex=-1 163 | 164 | [Key10] 165 | Caption=CE 166 | ShiftCaption= 167 | KeyValue=-1 168 | ShiftKeyValue=-1 169 | SpecialKey=0 170 | Color=10526880 171 | ColorDown=8421504 172 | TextColor=0 173 | TextColorDown=0 174 | Width=60 175 | Height=30 176 | X=31 177 | Y=91 178 | ImageIndex=-1 179 | 180 | [KeyBoard] 181 | Width=92 182 | Height=122 183 | -------------------------------------------------------------------------------- /4DSystems/AquariumController/AquariumController.ImgData/KB2.kbd: -------------------------------------------------------------------------------- 1 | [Keys] 2 | Count=12 3 | 4 | [Key0] 5 | Caption=7 6 | ShiftCaption= 7 | KeyValue=-1 8 | ShiftKeyValue=-1 9 | SpecialKey=0 10 | Color=12632256 11 | ColorDown=8421504 12 | TextColor=0 13 | TextColorDown=0 14 | Width=30 15 | Height=30 16 | X=1 17 | Y=1 18 | ImageIndex=-1 19 | 20 | [Key1] 21 | Caption=8 22 | ShiftCaption= 23 | KeyValue=-1 24 | ShiftKeyValue=-1 25 | SpecialKey=0 26 | Color=12632256 27 | ColorDown=8421504 28 | TextColor=0 29 | TextColorDown=0 30 | Width=30 31 | Height=30 32 | X=31 33 | Y=1 34 | ImageIndex=-1 35 | 36 | [Key2] 37 | Caption=9 38 | ShiftCaption= 39 | KeyValue=-1 40 | ShiftKeyValue=-1 41 | SpecialKey=0 42 | Color=12632256 43 | ColorDown=8421504 44 | TextColor=0 45 | TextColorDown=0 46 | Width=30 47 | Height=30 48 | X=61 49 | Y=1 50 | ImageIndex=-1 51 | 52 | [Key3] 53 | Caption=4 54 | ShiftCaption= 55 | KeyValue=-1 56 | ShiftKeyValue=-1 57 | SpecialKey=0 58 | Color=12632256 59 | ColorDown=8421504 60 | TextColor=0 61 | TextColorDown=0 62 | Width=30 63 | Height=30 64 | X=1 65 | Y=31 66 | ImageIndex=-1 67 | 68 | [Key4] 69 | Caption=5 70 | ShiftCaption= 71 | KeyValue=-1 72 | ShiftKeyValue=-1 73 | SpecialKey=0 74 | Color=12632256 75 | ColorDown=8421504 76 | TextColor=0 77 | TextColorDown=0 78 | Width=30 79 | Height=30 80 | X=31 81 | Y=31 82 | ImageIndex=-1 83 | 84 | [Key5] 85 | Caption=6 86 | ShiftCaption= 87 | KeyValue=-1 88 | ShiftKeyValue=-1 89 | SpecialKey=0 90 | Color=12632256 91 | ColorDown=8421504 92 | TextColor=0 93 | TextColorDown=0 94 | Width=30 95 | Height=30 96 | X=61 97 | Y=31 98 | ImageIndex=-1 99 | 100 | [Key6] 101 | Caption=1 102 | ShiftCaption= 103 | KeyValue=-1 104 | ShiftKeyValue=-1 105 | SpecialKey=0 106 | Color=12632256 107 | ColorDown=8421504 108 | TextColor=0 109 | TextColorDown=0 110 | Width=30 111 | Height=30 112 | X=1 113 | Y=61 114 | ImageIndex=-1 115 | 116 | [Key7] 117 | Caption=2 118 | ShiftCaption= 119 | KeyValue=-1 120 | ShiftKeyValue=-1 121 | SpecialKey=0 122 | Color=12632256 123 | ColorDown=8421504 124 | TextColor=0 125 | TextColorDown=0 126 | Width=30 127 | Height=30 128 | X=31 129 | Y=61 130 | ImageIndex=-1 131 | 132 | [Key8] 133 | Caption=3 134 | ShiftCaption= 135 | KeyValue=-1 136 | ShiftKeyValue=-1 137 | SpecialKey=0 138 | Color=12632256 139 | ColorDown=8421504 140 | TextColor=0 141 | TextColorDown=0 142 | Width=30 143 | Height=30 144 | X=61 145 | Y=61 146 | ImageIndex=-1 147 | 148 | [Key9] 149 | Caption=0 150 | ShiftCaption= 151 | KeyValue=-1 152 | ShiftKeyValue=-1 153 | SpecialKey=0 154 | Color=12632256 155 | ColorDown=8421504 156 | TextColor=0 157 | TextColorDown=0 158 | Width=30 159 | Height=30 160 | X=1 161 | Y=91 162 | ImageIndex=-1 163 | 164 | [Key10] 165 | Caption=. 166 | ShiftCaption= 167 | KeyValue=-1 168 | ShiftKeyValue=-1 169 | SpecialKey=0 170 | Color=12632256 171 | ColorDown=8421504 172 | TextColor=0 173 | TextColorDown=0 174 | Width=30 175 | Height=30 176 | X=31 177 | Y=91 178 | ImageIndex=-1 179 | 180 | [Key11] 181 | Caption=CE 182 | ShiftCaption= 183 | KeyValue=-1 184 | ShiftKeyValue=-1 185 | SpecialKey=0 186 | Color=10526880 187 | ColorDown=8421504 188 | TextColor=0 189 | TextColorDown=0 190 | Width=30 191 | Height=30 192 | X=61 193 | Y=91 194 | ImageIndex=-1 195 | 196 | [KeyBoard] 197 | Width=92 198 | Height=122 199 | -------------------------------------------------------------------------------- /4DSystems/AquariumController/AquariumController.ImgData/KB3.kbd: -------------------------------------------------------------------------------- 1 | [Keys] 2 | Count=12 3 | 4 | [Key0] 5 | Caption=7 6 | ShiftCaption= 7 | KeyValue=-1 8 | ShiftKeyValue=-1 9 | SpecialKey=0 10 | Color=12632256 11 | ColorDown=8421504 12 | TextColor=0 13 | TextColorDown=0 14 | Width=30 15 | Height=30 16 | X=1 17 | Y=1 18 | ImageIndex=-1 19 | 20 | [Key1] 21 | Caption=8 22 | ShiftCaption= 23 | KeyValue=-1 24 | ShiftKeyValue=-1 25 | SpecialKey=0 26 | Color=12632256 27 | ColorDown=8421504 28 | TextColor=0 29 | TextColorDown=0 30 | Width=30 31 | Height=30 32 | X=31 33 | Y=1 34 | ImageIndex=-1 35 | 36 | [Key2] 37 | Caption=9 38 | ShiftCaption= 39 | KeyValue=-1 40 | ShiftKeyValue=-1 41 | SpecialKey=0 42 | Color=12632256 43 | ColorDown=8421504 44 | TextColor=0 45 | TextColorDown=0 46 | Width=30 47 | Height=30 48 | X=61 49 | Y=1 50 | ImageIndex=-1 51 | 52 | [Key3] 53 | Caption=4 54 | ShiftCaption= 55 | KeyValue=-1 56 | ShiftKeyValue=-1 57 | SpecialKey=0 58 | Color=12632256 59 | ColorDown=8421504 60 | TextColor=0 61 | TextColorDown=0 62 | Width=30 63 | Height=30 64 | X=1 65 | Y=31 66 | ImageIndex=-1 67 | 68 | [Key4] 69 | Caption=5 70 | ShiftCaption= 71 | KeyValue=-1 72 | ShiftKeyValue=-1 73 | SpecialKey=0 74 | Color=12632256 75 | ColorDown=8421504 76 | TextColor=0 77 | TextColorDown=0 78 | Width=30 79 | Height=30 80 | X=31 81 | Y=31 82 | ImageIndex=-1 83 | 84 | [Key5] 85 | Caption=6 86 | ShiftCaption= 87 | KeyValue=-1 88 | ShiftKeyValue=-1 89 | SpecialKey=0 90 | Color=12632256 91 | ColorDown=8421504 92 | TextColor=0 93 | TextColorDown=0 94 | Width=30 95 | Height=30 96 | X=61 97 | Y=31 98 | ImageIndex=-1 99 | 100 | [Key6] 101 | Caption=1 102 | ShiftCaption= 103 | KeyValue=-1 104 | ShiftKeyValue=-1 105 | SpecialKey=0 106 | Color=12632256 107 | ColorDown=8421504 108 | TextColor=0 109 | TextColorDown=0 110 | Width=30 111 | Height=30 112 | X=1 113 | Y=61 114 | ImageIndex=-1 115 | 116 | [Key7] 117 | Caption=2 118 | ShiftCaption= 119 | KeyValue=-1 120 | ShiftKeyValue=-1 121 | SpecialKey=0 122 | Color=12632256 123 | ColorDown=8421504 124 | TextColor=0 125 | TextColorDown=0 126 | Width=30 127 | Height=30 128 | X=31 129 | Y=61 130 | ImageIndex=-1 131 | 132 | [Key8] 133 | Caption=3 134 | ShiftCaption= 135 | KeyValue=-1 136 | ShiftKeyValue=-1 137 | SpecialKey=0 138 | Color=12632256 139 | ColorDown=8421504 140 | TextColor=0 141 | TextColorDown=0 142 | Width=30 143 | Height=30 144 | X=61 145 | Y=61 146 | ImageIndex=-1 147 | 148 | [Key9] 149 | Caption=0 150 | ShiftCaption= 151 | KeyValue=-1 152 | ShiftKeyValue=-1 153 | SpecialKey=0 154 | Color=12632256 155 | ColorDown=8421504 156 | TextColor=0 157 | TextColorDown=0 158 | Width=30 159 | Height=30 160 | X=1 161 | Y=91 162 | ImageIndex=-1 163 | 164 | [Key10] 165 | Caption=: 166 | ShiftCaption= 167 | KeyValue=-1 168 | ShiftKeyValue=-1 169 | SpecialKey=0 170 | Color=12632256 171 | ColorDown=8421504 172 | TextColor=0 173 | TextColorDown=0 174 | Width=30 175 | Height=30 176 | X=31 177 | Y=91 178 | ImageIndex=-1 179 | 180 | [Key11] 181 | Caption=CE 182 | ShiftCaption= 183 | KeyValue=-1 184 | ShiftKeyValue=-1 185 | SpecialKey=0 186 | Color=10526880 187 | ColorDown=8421504 188 | TextColor=0 189 | TextColorDown=0 190 | Width=30 191 | Height=30 192 | X=61 193 | Y=91 194 | ImageIndex=-1 195 | 196 | [KeyBoard] 197 | Width=92 198 | Height=122 199 | -------------------------------------------------------------------------------- /4DSystems/AquariumController/AquariumController.ImgData/Tahoma19____A.font: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/AquariumController/AquariumController.ImgData/Tahoma19____A.font -------------------------------------------------------------------------------- /4DSystems/AquariumController/AquariumController.ImgData/Tahoma19b___A.font: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/AquariumController/AquariumController.ImgData/Tahoma19b___A.font -------------------------------------------------------------------------------- /4DSystems/AquariumController/AquariumController.ImgData/WINPANEL-RED.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/4DSystems/AquariumController/AquariumController.ImgData/WINPANEL-RED.bmp -------------------------------------------------------------------------------- /Arduino/AquariumController/AQUA_adc141s626.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Library: ADC141S626 4 | Version: 2.1 5 | Author: Rastislav Birka 6 | */ 7 | 8 | #include 9 | #include "AQUA_adc141s626.h" 10 | 11 | /* 12 | Public Functions 13 | */ 14 | 15 | void AQUA_adc141s626::init(uint8_t voutPin, uint8_t misoPin, uint8_t mosiPin, uint8_t sclkPin, uint8_t ssPin) { 16 | _voutPin = voutPin; 17 | _misoPin = misoPin; 18 | _mosiPin = mosiPin; 19 | _sclkPin = sclkPin; 20 | _ssPin = ssPin; 21 | } 22 | 23 | int16_t AQUA_adc141s626::getValue() { 24 | int16_t value = 0; 25 | return value; 26 | } 27 | 28 | /* 29 | Private Functions 30 | */ 31 | 32 | -------------------------------------------------------------------------------- /Arduino/AquariumController/AQUA_adc141s626.h: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Library: ADC141S626 4 | Version: 2.1 5 | Author: Rastislav Birka 6 | */ 7 | 8 | #ifndef AQUA_adc141s626_h 9 | #define AQUA_adc141s626_h 10 | 11 | class AQUA_adc141s626 { 12 | public: 13 | void init(uint8_t _voutPin, uint8_t _misoPin = 50, uint8_t _mosiPin = 51, uint8_t _sclkPin = 52, uint8_t _ssPin = 53); 14 | int16_t getValue(); 15 | 16 | private: 17 | uint8_t _voutPin, _misoPin, _mosiPin, _sclkPin, _ssPin; 18 | }; 19 | #endif 20 | -------------------------------------------------------------------------------- /Arduino/AquariumController/AQUA_ads1115.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Library: ADS1115 4 | Version: 2.1 5 | Author: Rastislav Birka 6 | */ 7 | 8 | #include 9 | #include "AQUA_ads1115.h" 10 | 11 | /* 12 | Public Functions 13 | */ 14 | 15 | void AQUA_ads1115::init(uint8_t sdaPin, uint8_t sclPin) { 16 | _sdaPin = sdaPin; 17 | _sclPin = sclPin; 18 | } 19 | 20 | int16_t AQUA_ads1115::getValue() { 21 | int16_t value = 0; 22 | return value; 23 | } 24 | 25 | /* 26 | Private Functions 27 | */ 28 | 29 | -------------------------------------------------------------------------------- /Arduino/AquariumController/AQUA_ads1115.h: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Library: ADS1115 4 | Version: 2.1 5 | Author: Rastislav Birka 6 | */ 7 | 8 | #ifndef AQUA_ads1115_h 9 | #define AQUA_ads1115_h 10 | 11 | class AQUA_ads1115 { 12 | public: 13 | void init(uint8_t sdaPin, uint8_t sclPin); 14 | int16_t getValue(); 15 | 16 | private: 17 | uint8_t _sdaPin, _sclPin; 18 | }; 19 | #endif 20 | -------------------------------------------------------------------------------- /Arduino/AquariumController/AQUA_lcd.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Library: LCD - 4D Systems - Visi Genie 4 | Version: 1.0 5 | Author: Rastislav Birka 6 | */ 7 | 8 | #include 9 | #include 10 | #include "AQUA_lcd.h" 11 | 12 | void AQUA_lcd::init(uint8_t timeout_address) { 13 | _timeoutAddress = timeout_address; 14 | eeprom_busy_wait(); 15 | _timeout = eeprom_read_word((const uint16_t *)_timeoutAddress); 16 | if(_timeout == 0xFFFF) { 17 | _timeout = 30; //default timeout is 30 seconds 18 | } 19 | _actualForm = GENIE_FORM_MAIN; 20 | } 21 | 22 | uint16_t AQUA_lcd::getTimeout(void) { 23 | return _timeout; 24 | } 25 | 26 | void AQUA_lcd::setTimeout(uint16_t timeout) { 27 | if(timeout != _timeout) { 28 | _timeout = timeout; 29 | eeprom_busy_wait(); 30 | eeprom_write_word((uint16_t *)_timeoutAddress, _timeout); 31 | } 32 | } 33 | 34 | uint8_t AQUA_lcd::getActualForm(void) { 35 | return _actualForm; 36 | } 37 | 38 | void AQUA_lcd::setActualForm(uint8_t form) { 39 | if(form >= GENIE_FORM_MAIN && form <= GENIE_FORM_CALIBRATION) { 40 | _actualForm = form; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Arduino/AquariumController/AQUA_lcd.h: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Library: LCD - 4D Systems - Visi Genie 4 | Version: 1.0 5 | Author: Rastislav Birka 6 | */ 7 | 8 | #ifndef AQUA_lcd_h 9 | #define AQUA_lcd_h 10 | 11 | #define GENIE_FORM_MAIN 0 12 | #define GENIE_FORM_SLEEP 1 13 | #define GENIE_FORM_SET_TIME 2 14 | #define GENIE_FORM_SET_ALARM 3 15 | #define GENIE_FORM_SET_TIMER 4 16 | #define GENIE_FORM_CALIBRATION 5 17 | #define GENIE_FORM_CALIBRATION_SHOW 6 18 | 19 | #define GENIE_BTN_WAKEUP 0 20 | #define GENIE_BTN_SLEEP 0 21 | #define GENIE_BTN_SET_TIME 1 22 | #define GENIE_BTN_CALIBRATION_TEMP 2 23 | #define GENIE_BTN_CALIBRATION_PH 3 24 | #define GENIE_BTN_CALIBRATION_ORP 4 25 | #define GENIE_BTN_SET_R1 5 26 | #define GENIE_BTN_SET_R2 6 27 | #define GENIE_BTN_SET_R3 7 28 | #define GENIE_BTN_SET_R4 8 29 | #define GENIE_BTN_SET_R5 9 30 | #define GENIE_BTN_SET_R6 10 31 | #define GENIE_BTN_SET_R7 11 32 | #define GENIE_BTN_SET_R8 12 33 | 34 | #define GENIE_BTN_CONTROL_R1 0 35 | #define GENIE_BTN_CONTROL_R2 1 36 | #define GENIE_BTN_CONTROL_R3 2 37 | #define GENIE_BTN_CONTROL_R4 3 38 | #define GENIE_BTN_CONTROL_R5 4 39 | #define GENIE_BTN_CONTROL_R6 5 40 | #define GENIE_BTN_CONTROL_R7 6 41 | #define GENIE_BTN_CONTROL_R8 7 42 | #define GENIE_BTN_ONOFF_R1 8 43 | #define GENIE_BTN_ONOFF_R2 9 44 | #define GENIE_BTN_ONOFF_R3 10 45 | #define GENIE_BTN_ONOFF_R4 11 46 | #define GENIE_BTN_ONOFF_R5 12 47 | #define GENIE_BTN_ONOFF_R6 13 48 | #define GENIE_BTN_ONOFF_R7 14 49 | #define GENIE_BTN_ONOFF_R8 15 50 | 51 | #define GENIE_BTN_BACK_TIME 13 52 | #define GENIE_BTN_BACK_ALARM 14 53 | #define GENIE_BTN_BACK_TIMER 15 54 | #define GENIE_BTN_BACK_CALIBRATION 16 55 | 56 | #define GENIE_BTN_SET_DAY 17 57 | #define GENIE_BTN_SET_MONTH 18 58 | #define GENIE_BTN_SET_YEAR 19 59 | #define GENIE_BTN_SET_HOUR 21 60 | #define GENIE_BTN_SET_MIN 22 61 | #define GENIE_BTN_SET_TIMEOUT 23 62 | #define GENIE_BTN_SAVE_DATE 24 63 | #define GENIE_BTN_SAVE_TIME 25 64 | #define GENIE_BTN_SAVE_TIMEOUT 27 65 | 66 | #define GENIE_BTN_ALARM_STATE 16 67 | #define GENIE_BTN_ALARM_SET_START 28 68 | #define GENIE_BTN_ALARM_SET_STOP 29 69 | #define GENIE_BTN_SAVE_ALARM 30 70 | 71 | #define GENIE_BTN_TIMER1_STATE 17 72 | #define GENIE_BTN_TIMER2_STATE 18 73 | #define GENIE_BTN_TIMER3_STATE 19 74 | #define GENIE_BTN_TIMER4_STATE 20 75 | #define GENIE_BTN_TIMER1_SET_START 31 76 | #define GENIE_BTN_TIMER1_SET_STOP 32 77 | #define GENIE_BTN_TIMER2_SET_START 33 78 | #define GENIE_BTN_TIMER2_SET_STOP 34 79 | #define GENIE_BTN_TIMER3_SET_START 35 80 | #define GENIE_BTN_TIMER3_SET_STOP 36 81 | #define GENIE_BTN_TIMER4_SET_START 37 82 | #define GENIE_BTN_TIMER4_SET_STOP 38 83 | #define GENIE_BTN_SAVE_TIMER1 39 84 | #define GENIE_BTN_SAVE_TIMER2 40 85 | #define GENIE_BTN_SAVE_TIMER3 41 86 | #define GENIE_BTN_SAVE_TIMER4 42 87 | 88 | #define GENIE_BTN_CAL1_STATE 21 89 | #define GENIE_BTN_CAL2_STATE 22 90 | #define GENIE_BTN_CAL3_STATE 23 91 | #define GENIE_BTN_CAL1_SET_REF 43 92 | #define GENIE_BTN_CAL2_SET_REF 44 93 | #define GENIE_BTN_CAL3_SET_REF 45 94 | #define GENIE_BTN_CAL1_READ_ACT 46 95 | #define GENIE_BTN_CAL2_READ_ACT 47 96 | #define GENIE_BTN_CAL3_READ_ACT 48 97 | #define GENIE_BTN_SAVE_CALIBRATION 49 98 | 99 | #define GENIE_KEYBOARD_TIME 0 100 | #define GENIE_KEYBOARD_ALARM 1 101 | #define GENIE_KEYBOARD_TIMER 2 102 | #define GENIE_KEYBOARD_CALIBRATION 3 103 | #define GENIE_KEYBOARD_CLEAR_KEY 99 104 | 105 | #define GENIE_GAUGE_CALIBRATION 0 106 | 107 | #define GENIE_STR_TIME 0 108 | #define GENIE_STR_TEMP 1 109 | #define GENIE_STR_PH 2 110 | #define GENIE_STR_ORP 3 111 | 112 | #define GENIE_STR_TIME_KEY 4 113 | #define GENIE_STR_DAY 5 114 | #define GENIE_STR_MONTH 6 115 | #define GENIE_STR_YEAR 7 116 | #define GENIE_STR_HOUR 9 117 | #define GENIE_STR_MIN 10 118 | #define GENIE_STR_SLEEP_TIMEOUT 11 119 | 120 | #define GENIE_STR_ALARM_INFO 12 121 | #define GENIE_STR_ALARM_KEY 13 122 | #define GENIE_STR_ALARM_START 14 123 | #define GENIE_STR_ALARM_STOP 15 124 | 125 | #define GENIE_STR_TIMER_INFO 16 126 | #define GENIE_STR_TIMER_KEY 17 127 | #define GENIE_STR_TIMER1_START 18 128 | #define GENIE_STR_TIMER1_STOP 19 129 | #define GENIE_STR_TIMER2_START 20 130 | #define GENIE_STR_TIMER2_STOP 21 131 | #define GENIE_STR_TIMER3_START 22 132 | #define GENIE_STR_TIMER3_STOP 23 133 | #define GENIE_STR_TIMER4_START 24 134 | #define GENIE_STR_TIMER4_STOP 25 135 | 136 | #define GENIE_STR_CAL_INFO 26 137 | #define GENIE_STR_CAL_KEY 27 138 | #define GENIE_STR_CAl1_REF_OLD 28 139 | #define GENIE_STR_CAl2_REF_OLD 29 140 | #define GENIE_STR_CAl3_REF_OLD 30 141 | #define GENIE_STR_CAl1_REF_NEW 31 142 | #define GENIE_STR_CAl2_REF_NEW 32 143 | #define GENIE_STR_CAl3_REF_NEW 33 144 | #define GENIE_STR_CAl1_ACT_OLD 34 145 | #define GENIE_STR_CAl2_ACT_OLD 35 146 | #define GENIE_STR_CAl3_ACT_OLD 36 147 | #define GENIE_STR_CAl1_ACT_NEW 37 148 | #define GENIE_STR_CAl2_ACT_NEW 38 149 | #define GENIE_STR_CAl3_ACT_NEW 39 150 | 151 | #define GENIE_STR_INFO_TIME 40 152 | #define GENIE_STR_INFO_ALARM 41 153 | #define GENIE_STR_INFO_TIMER 42 154 | #define GENIE_STR_INFO_CALIBRATION 43 155 | #define GENIE_STR_ACTUAL_VALUE 44 156 | 157 | #define GENIE_CALIBRATION_OFF 0 158 | #define GENIE_CALIBRATION_TEMP 1 159 | #define GENIE_CALIBRATION_PH 2 160 | #define GENIE_CALIBRATION_ORP 3 161 | 162 | class AQUA_lcd { 163 | public: 164 | void init(uint8_t timeout_address); 165 | uint16_t getTimeout(void); 166 | void setTimeout(uint16_t timeout); 167 | uint8_t getActualForm(void); 168 | void setActualForm(uint8_t form); 169 | 170 | private: 171 | uint16_t _timeout; 172 | uint8_t _timeoutAddress; 173 | uint8_t _actualForm; 174 | }; 175 | #endif 176 | -------------------------------------------------------------------------------- /Arduino/AquariumController/AQUA_orp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Library: ORP 4 | Version: 2.1 5 | Author: Rastislav Birka 6 | */ 7 | 8 | #include 9 | #include 10 | #include "AQUA_orp.h" 11 | 12 | /* 13 | Public Functions 14 | */ 15 | 16 | void AQUA_orp::init(uint8_t voutPin, uint8_t vocmPin, uint8_t calibrate_points, uint8_t calibrate_address, int vRef, uint8_t adc_bit) { 17 | uint16_t value, position; 18 | uint8_t i; 19 | bool negative; 20 | 21 | _voutPin = voutPin; 22 | _vocmPin = vocmPin; 23 | _pointCount = calibrate_points; 24 | _calibrateAddress = calibrate_address; 25 | _constPerUnit = (float)vRef/(pow(2,adc_bit)-1.0); 26 | _calData = new AQUA_orpCalibrationPoint[_pointCount]; 27 | _usedData = new AQUA_orpCalibrationPoint[_pointCount]; 28 | _const = new float[(_pointCount - 1)*2]; 29 | 30 | position = 0; 31 | for(i = 0; i < _pointCount; i++) { 32 | eeprom_busy_wait(); 33 | value = eeprom_read_word((const uint16_t *)(_calibrateAddress + position)); 34 | if(value == 0xFFFF) { //address wasn't set yet 35 | _calData[i].state = 0; 36 | _calData[i].refValue = 0; 37 | _calData[i].actValue = 0; 38 | position+= 4; 39 | } else { 40 | _calData[i].state = (bool)(value & 32768); 41 | if(_calData[i].state == 1) { 42 | value-= 32768; 43 | } 44 | negative = (bool)(value & 16384); 45 | if(negative == 1) { 46 | value = 0 - (value - 16384); 47 | } 48 | _calData[i].refValue = value; 49 | position+= 2; 50 | eeprom_busy_wait(); 51 | value = eeprom_read_word((const uint16_t *)(_calibrateAddress + position)); 52 | negative = (bool)(value & 16384); 53 | if(negative == 1) { 54 | value = 0 - (value - 16384); 55 | } 56 | _calData[i].actValue = value; 57 | position+= 2; 58 | } 59 | } 60 | _setCalibrationValues(); 61 | useInternalADC(); 62 | objADC141S626 = new AQUA_adc141s626; 63 | objADS1115 = new AQUA_ads1115; 64 | } 65 | 66 | void AQUA_orp::useInternalADC() { 67 | _adc = 0; 68 | } 69 | 70 | void AQUA_orp::useADC141S626(uint8_t voutPin, uint8_t misoPin, uint8_t mosiPin, uint8_t sclkPin, uint8_t ssPin) { 71 | _adc = 1; 72 | objADC141S626->init(voutPin, misoPin, mosiPin, sclkPin, ssPin); 73 | } 74 | 75 | void AQUA_orp::useADS1115(uint8_t sdaPin, uint8_t sclPin) { 76 | _adc = 2; 77 | objADS1115->init(sdaPin, sclPin); 78 | } 79 | 80 | /* 81 | LMP91200 82 | ORP = VOUT - VOCM 83 | */ 84 | int AQUA_orp::getORP(bool calibrate) { 85 | uint8_t i; 86 | int res; 87 | 88 | switch (_adc) { 89 | case 2: //external ADS1115 90 | res = (float)objADS1115->getValue(); 91 | break; 92 | case 1: //external ADC141S626 93 | res = (float)objADC141S626->getValue(); 94 | break; 95 | default: //internal arduino ADC 96 | res = _readInternalADC(); 97 | } 98 | 99 | if(calibrate == 0) { 100 | if(_usedPoints == 1) { 101 | res+= _const[0]; 102 | } else if(_usedPoints > 1) { 103 | if(res >= _usedData[_usedPoints-1].actValue) { 104 | res = _const[(_usedPoints-2)*2]*res + _const[(_usedPoints-2)*2 + 1]; 105 | } else { 106 | for(i = 1; i < _usedPoints; i++) { 107 | if(res <= _usedData[i].actValue) { 108 | res = _const[(i-1)*2]*res + _const[(i-1)*2 + 1]; 109 | break; 110 | } 111 | } 112 | } 113 | } 114 | } 115 | 116 | return res; 117 | } 118 | 119 | bool AQUA_orp::calibration(uint8_t point, AQUA_orpCalibrationPoint *values) { 120 | bool res = false; 121 | 122 | if(point < _pointCount && point >= 0 && values->refValue <= 1999 && values->refValue >= -1999 && values->actValue <= 1999 && values->actValue >= -1999) { 123 | if(values->state != _calData[point].state || values->refValue != _calData[point].refValue || values->actValue != _calData[point].actValue) { 124 | _calData[point].state = values->state; 125 | _calData[point].refValue = values->refValue; 126 | _calData[point].actValue = values->actValue; 127 | uint16_t plusValue = 0; 128 | if(_calData[point].state == 1) { 129 | plusValue+= 32768; 130 | } 131 | if(_calData[point].refValue < 0) { 132 | plusValue+= 16384; 133 | } 134 | uint16_t position = point*4; 135 | eeprom_busy_wait(); 136 | eeprom_write_word((uint16_t *)(_calibrateAddress + position), abs(_calData[point].refValue) + plusValue); 137 | plusValue = 0; 138 | if(_calData[point].actValue < 0) { 139 | plusValue+= 16384; 140 | } 141 | position+= 2; 142 | eeprom_busy_wait(); 143 | eeprom_write_word((uint16_t *)(_calibrateAddress + position), abs(_calData[point].actValue) + plusValue); 144 | _setCalibrationValues(); 145 | res = true; 146 | } 147 | } 148 | return res; 149 | } 150 | 151 | AQUA_orpCalibrationPoint AQUA_orp::readCalibrationPoint(uint8_t point) { 152 | AQUA_orpCalibrationPoint calPoint; 153 | if(point < _pointCount && point >= 0) { 154 | calPoint.state = _calData[point].state; 155 | calPoint.refValue = _calData[point].refValue; 156 | calPoint.actValue = _calData[point].actValue; 157 | } else { 158 | calPoint.state = 0; 159 | calPoint.refValue = 0; 160 | calPoint.actValue = 0; 161 | } 162 | return calPoint; 163 | } 164 | 165 | /* 166 | Private Functions 167 | */ 168 | 169 | /* 170 | c1 = (ref2 - ref1)/(act2 - act1) 171 | c2 = ref2 - c1*act2 172 | orp = c1*SensorValue + c2 173 | */ 174 | void AQUA_orp::_setCalibrationValues() { 175 | uint8_t i,j; 176 | bool isCorrect; 177 | 178 | _usedPoints = 0; 179 | for(i = 0; i < _pointCount; i++) { 180 | if(_calData[i].state == 1 && _calData[i].actValue > 0 && _calData[i].refValue > 0) { 181 | if(_usedPoints > 0) { 182 | isCorrect = 1; 183 | for(j = 0; j < _usedPoints; j++) { 184 | if(_calData[i].actValue == _usedData[j].actValue || _calData[i].refValue == _usedData[j].refValue) { 185 | isCorrect = 0; 186 | break; 187 | } 188 | } 189 | if(isCorrect == 1) { 190 | j = _usedPoints; 191 | for(j; j > 0 && _usedData[j-1].actValue > _calData[i].actValue; --j) { 192 | _usedData[j].state = _usedData[j-1].state; 193 | _usedData[j].refValue = _usedData[j-1].refValue; 194 | _usedData[j].actValue = _usedData[j-1].actValue; 195 | } 196 | _usedData[j].state = _calData[i].state; 197 | _usedData[j].refValue = _calData[i].refValue; 198 | _usedData[j].actValue = _calData[i].actValue; 199 | _usedPoints++; 200 | } 201 | } else { 202 | _usedData[_usedPoints].state = _calData[i].state; 203 | _usedData[_usedPoints].refValue = _calData[i].refValue; 204 | _usedData[_usedPoints].actValue = _calData[i].actValue; 205 | _usedPoints++; 206 | } 207 | } 208 | } 209 | if(_usedPoints == 1) { 210 | _const[0] = (_usedData[0].refValue - _usedData[0].actValue); 211 | } else if(_usedPoints > 1) { 212 | for(i = 0; i < _usedPoints - 1; i++) { 213 | _const[i*2] = (_usedData[i+1].refValue - _usedData[i].refValue)/(_usedData[i+1].actValue - _usedData[i].actValue); 214 | _const[i*2 + 1] = _usedData[i+1].refValue - _const[i*2]*_usedData[i+1].actValue; 215 | } 216 | } 217 | } 218 | 219 | /* 220 | LMP91200 221 | ORP = VOUT - VOCM 222 | */ 223 | int AQUA_orp::_readInternalADC() { 224 | int tmp, total = 0; 225 | int values[120]; 226 | int res; 227 | uint8_t i, j; 228 | 229 | for(i = 0; i < 120; i++) { 230 | values[i] = analogRead(_voutPin) - analogRead(_vocmPin); 231 | } 232 | for(i = 0; i < 119; i++) { 233 | for(j = i+1; j < 120; j++) { 234 | if(values[i] > values[j]) { 235 | tmp = values[i]; 236 | values[i] = values[j]; 237 | values[j] = tmp; 238 | } 239 | } 240 | } 241 | for(i = 10; i < 110; i++) { 242 | total+= values[i]; 243 | } 244 | res = round((float)(total/100.0)*_constPerUnit); 245 | return res; 246 | } 247 | -------------------------------------------------------------------------------- /Arduino/AquariumController/AQUA_orp.h: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Library: ORP 4 | Version: 2.1 5 | Author: Rastislav Birka 6 | */ 7 | 8 | #ifndef AQUA_orp_h 9 | #define AQUA_orp_h 10 | 11 | #include "AQUA_adc141s626.h" 12 | #include "AQUA_ads1115.h" 13 | 14 | typedef struct { 15 | bool state; 16 | int refValue; 17 | int actValue; 18 | } AQUA_orpCalibrationPoint; 19 | 20 | class AQUA_orp { 21 | public: 22 | void init(uint8_t voutPin, uint8_t vocmPin, uint8_t calibrate_points, uint8_t calibrate_address, int vRef = 5000, uint8_t adc_bit = 10); 23 | void useInternalADC(); 24 | void useADC141S626(uint8_t _voutPin, uint8_t _misoPin = 50, uint8_t _mosiPin = 51, uint8_t _sclkPin = 52, uint8_t _ssPin = 53); 25 | void useADS1115(uint8_t sdaPin, uint8_t sclPin); 26 | int getORP(bool calibrate = 0); 27 | bool calibration(uint8_t point, AQUA_orpCalibrationPoint *values); 28 | AQUA_orpCalibrationPoint readCalibrationPoint(uint8_t point); 29 | 30 | private: 31 | uint8_t _adc; 32 | uint8_t _voutPin, _vocmPin; 33 | uint8_t _pointCount; 34 | uint8_t _calibrateAddress; 35 | AQUA_orpCalibrationPoint* _calData; 36 | AQUA_orpCalibrationPoint* _usedData; 37 | uint8_t _usedPoints; 38 | float* _const; 39 | float _constPerUnit; 40 | AQUA_adc141s626 *objADC141S626; 41 | AQUA_ads1115 *objADS1115; 42 | 43 | void _setCalibrationValues(); 44 | int _readInternalADC(); 45 | }; 46 | #endif 47 | -------------------------------------------------------------------------------- /Arduino/AquariumController/AQUA_ph.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Library: PH 4 | Version: 2.1 5 | Author: Rastislav Birka 6 | */ 7 | 8 | #include 9 | #include 10 | #include "AQUA_ph.h" 11 | 12 | /* 13 | Public Functions 14 | */ 15 | 16 | void AQUA_ph::init(uint8_t voutPin, uint8_t vocmPin, uint8_t calibrate_points, uint8_t calibrate_address, int vRef, uint8_t adc_bit, float alpha) { 17 | uint16_t value, position; 18 | uint8_t i; 19 | 20 | _voutPin = voutPin; 21 | _vocmPin = vocmPin; 22 | _pointCount = calibrate_points; 23 | _calibrateAddress = calibrate_address; 24 | _alpha = alpha; 25 | _constPerUnit = (float)vRef/(pow(2,adc_bit)-1.0); 26 | _calData = new AQUA_phCalibrationPoint[_pointCount]; 27 | _usedData = new AQUA_phCalibrationPoint[_pointCount]; 28 | _const = new float[(_pointCount - 1)*2]; 29 | 30 | position = 0; 31 | for(i = 0; i < _pointCount; i++) { 32 | eeprom_busy_wait(); 33 | value = eeprom_read_word((const uint16_t *)(_calibrateAddress + position)); 34 | if(value == 0xFFFF) { //address wasn't set yet 35 | _calData[i].state = 0; 36 | _calData[i].refValue = 0; 37 | _calData[i].actValue = 0; 38 | position+= 4; 39 | } else { 40 | _calData[i].state = (bool)(value & 32768); 41 | if(_calData[i].state == 1) { 42 | value-= 32768; 43 | } 44 | _calData[i].refValue = (float)value/100.0; 45 | position+= 2; 46 | eeprom_busy_wait(); 47 | value = eeprom_read_word((const uint16_t *)(_calibrateAddress + position)); 48 | _calData[i].actValue = (float)value/100.0; 49 | position+= 2; 50 | } 51 | } 52 | _setCalibrationValues(); 53 | useInternalADC(); 54 | objADC141S626 = new AQUA_adc141s626; 55 | objADS1115 = new AQUA_ads1115; 56 | } 57 | 58 | void AQUA_ph::useInternalADC() { 59 | _adc = 0; 60 | } 61 | 62 | void AQUA_ph::useADC141S626(uint8_t voutPin, uint8_t misoPin, uint8_t mosiPin, uint8_t sclkPin, uint8_t ssPin) { 63 | _adc = 1; 64 | objADC141S626->init(voutPin, misoPin, mosiPin, sclkPin, ssPin); 65 | } 66 | 67 | void AQUA_ph::useADS1115(uint8_t sdaPin, uint8_t sclPin) { 68 | _adc = 2; 69 | objADS1115->init(sdaPin, sclPin); 70 | } 71 | 72 | /* 73 | LMP91200 74 | pH = 7 + (VOUT - VOCM)/alpha 75 | alpha = -59.16mV/pH @ 25°C 76 | */ 77 | float AQUA_ph::getPH(bool calibrate) { 78 | uint8_t i; 79 | float res, adcValue; 80 | 81 | switch (_adc) { 82 | case 2: //external ADS1115 83 | adcValue = (float)objADS1115->getValue(); 84 | break; 85 | case 1: //external ADC141S626 86 | adcValue = (float)objADC141S626->getValue(); 87 | break; 88 | default: //internal arduino ADC 89 | adcValue = _readInternalADC(); 90 | } 91 | res = 7.00 + adcValue/(0.0 - _alpha); 92 | 93 | if(calibrate == 0) { 94 | if(_usedPoints == 1) { 95 | res+= _const[0]; 96 | } else if(_usedPoints > 1) { 97 | if(res >= _usedData[_usedPoints-1].actValue) { 98 | res = _const[(_usedPoints-2)*2]*res + _const[(_usedPoints-2)*2 + 1]; 99 | } else { 100 | for(i = 1; i < _usedPoints; i++) { 101 | if(res <= _usedData[i].actValue) { 102 | res = _const[(i-1)*2]*res + _const[(i-1)*2 + 1]; 103 | break; 104 | } 105 | } 106 | } 107 | } 108 | } 109 | 110 | return res; 111 | } 112 | 113 | bool AQUA_ph::calibration(uint8_t point, AQUA_phCalibrationPoint *values) { 114 | bool res = false; 115 | 116 | if(point < _pointCount && point >= 0 && values->refValue <= 1400 && values->refValue >= 0 && values->actValue <= 1400 && values->actValue >= 0) { 117 | if(values->state != _calData[point].state || values->refValue != _calData[point].refValue || values->actValue != _calData[point].actValue) { 118 | _calData[point].state = values->state; 119 | _calData[point].refValue = values->refValue; 120 | _calData[point].actValue = values->actValue; 121 | uint16_t plusValue = 0; 122 | if(_calData[point].state == 1) { 123 | plusValue+= 32768; 124 | } 125 | uint16_t position = point*4; 126 | eeprom_busy_wait(); 127 | eeprom_write_word((uint16_t *)(_calibrateAddress + position), _calData[point].refValue*100 + plusValue); 128 | position+= 2; 129 | eeprom_busy_wait(); 130 | eeprom_write_word((uint16_t *)(_calibrateAddress + position), _calData[point].actValue*100); 131 | _setCalibrationValues(); 132 | res = true; 133 | } 134 | } 135 | return res; 136 | } 137 | 138 | AQUA_phCalibrationPoint AQUA_ph::readCalibrationPoint(uint8_t point) { 139 | AQUA_phCalibrationPoint calPoint; 140 | if(point < _pointCount && point >= 0) { 141 | calPoint.state = _calData[point].state; 142 | calPoint.refValue = _calData[point].refValue; 143 | calPoint.actValue = _calData[point].actValue; 144 | } else { 145 | calPoint.state = 0; 146 | calPoint.refValue = 0; 147 | calPoint.actValue = 0; 148 | } 149 | return calPoint; 150 | } 151 | 152 | /* 153 | Private Functions 154 | */ 155 | 156 | /* 157 | c1 = (ref2 - ref1)/(act2 - act1) 158 | c2 = ref2 - c1*act2 159 | pH = c1*SensorValue + c2 160 | */ 161 | void AQUA_ph::_setCalibrationValues() { 162 | uint8_t i,j; 163 | bool isCorrect; 164 | 165 | _usedPoints = 0; 166 | for(i = 0; i < _pointCount; i++) { 167 | if(_calData[i].state == 1 && _calData[i].actValue > 0 && _calData[i].refValue > 0) { 168 | if(_usedPoints > 0) { 169 | isCorrect = 1; 170 | for(j = 0; j < _usedPoints; j++) { 171 | if(_calData[i].actValue == _usedData[j].actValue || _calData[i].refValue == _usedData[j].refValue) { 172 | isCorrect = 0; 173 | break; 174 | } 175 | } 176 | if(isCorrect == 1) { 177 | j = _usedPoints; 178 | for(j; j > 0 && _usedData[j-1].actValue > _calData[i].actValue; --j) { 179 | _usedData[j].state = _usedData[j-1].state; 180 | _usedData[j].refValue = _usedData[j-1].refValue; 181 | _usedData[j].actValue = _usedData[j-1].actValue; 182 | } 183 | _usedData[j].state = _calData[i].state; 184 | _usedData[j].refValue = _calData[i].refValue; 185 | _usedData[j].actValue = _calData[i].actValue; 186 | _usedPoints++; 187 | } 188 | } else { 189 | _usedData[_usedPoints].state = _calData[i].state; 190 | _usedData[_usedPoints].refValue = _calData[i].refValue; 191 | _usedData[_usedPoints].actValue = _calData[i].actValue; 192 | _usedPoints++; 193 | } 194 | } 195 | } 196 | if(_usedPoints == 1) { 197 | _const[0] = (_usedData[0].refValue - _usedData[0].actValue); 198 | } else if(_usedPoints > 1) { 199 | for(i = 0; i < _usedPoints - 1; i++) { 200 | _const[i*2] = (_usedData[i+1].refValue - _usedData[i].refValue)/(_usedData[i+1].actValue - _usedData[i].actValue); 201 | _const[i*2 + 1] = _usedData[i+1].refValue - _const[i*2]*_usedData[i+1].actValue; 202 | } 203 | } 204 | } 205 | 206 | /* 207 | LMP91200 208 | pH = 7 + (VOUT - VOCM)/alpha 209 | alpha = -59.16mV/pH @ 25°C 210 | */ 211 | float AQUA_ph::_readInternalADC() { 212 | int tmp, total = 0; 213 | int values[120]; 214 | float res; 215 | uint8_t i, j; 216 | 217 | for(i = 0; i < 120; i++) { 218 | values[i] = analogRead(_voutPin) - analogRead(_vocmPin); 219 | } 220 | for(i = 0; i < 119; i++) { 221 | for(j = i+1; j < 120; j++) { 222 | if(values[i] > values[j]) { 223 | tmp = values[i]; 224 | values[i] = values[j]; 225 | values[j] = tmp; 226 | } 227 | } 228 | } 229 | for(i = 10; i < 110; i++) { 230 | total+= values[i]; 231 | } 232 | res = (float)(total/100.0)*_constPerUnit; 233 | return res; 234 | } 235 | -------------------------------------------------------------------------------- /Arduino/AquariumController/AQUA_ph.h: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Library: PH 4 | Version: 2.1 5 | Author: Rastislav Birka 6 | */ 7 | 8 | #ifndef AQUA_ph_h 9 | #define AQUA_ph_h 10 | 11 | #include "AQUA_adc141s626.h" 12 | #include "AQUA_ads1115.h" 13 | 14 | typedef struct { 15 | bool state; 16 | float refValue; 17 | float actValue; 18 | } AQUA_phCalibrationPoint; 19 | 20 | class AQUA_ph { 21 | public: 22 | void init(uint8_t voutPin, uint8_t vocmPin, uint8_t calibrate_points, uint8_t calibrate_address, int vRef = 5000, uint8_t adc_bit = 10, float alpha = 59.16); 23 | void useInternalADC(); 24 | void useADC141S626(uint8_t _voutPin, uint8_t _misoPin = 50, uint8_t _mosiPin = 51, uint8_t _sclkPin = 52, uint8_t _ssPin = 53); 25 | void useADS1115(uint8_t sdaPin, uint8_t sclPin); 26 | float getPH(bool calibrate = 0); 27 | bool calibration(uint8_t point, AQUA_phCalibrationPoint *values); 28 | AQUA_phCalibrationPoint readCalibrationPoint(uint8_t point); 29 | 30 | private: 31 | uint8_t _adc; 32 | uint8_t _voutPin, _vocmPin; 33 | uint8_t _pointCount; 34 | uint8_t _calibrateAddress; 35 | AQUA_phCalibrationPoint* _calData; 36 | AQUA_phCalibrationPoint* _usedData; 37 | uint8_t _usedPoints; 38 | float* _const; 39 | float _alpha, _constPerUnit; 40 | AQUA_adc141s626 *objADC141S626; 41 | AQUA_ads1115 *objADS1115; 42 | 43 | void _setCalibrationValues(); 44 | float _readInternalADC(); 45 | }; 46 | #endif 47 | -------------------------------------------------------------------------------- /Arduino/AquariumController/AQUA_relay.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Library: Relay 4 | Version: 1.0 5 | Author: Rastislav Birka 6 | */ 7 | 8 | #include 9 | #include 10 | #include "AQUA_relay.h" 11 | 12 | /* 13 | Public Functions 14 | */ 15 | 16 | void AQUA_relay::init(uint8_t firstPin, uint8_t alarms, uint8_t timers, uint8_t timer_parts, uint8_t alarms_address, uint8_t timers_address) { 17 | uint16_t value, position; 18 | uint8_t i,j; 19 | bool negative; 20 | 21 | _firstPin = firstPin; 22 | _alarmCount = alarms; 23 | _timerCount = timers; 24 | _timerParts = timer_parts; 25 | _alarmAddress = alarms_address; 26 | _timerAddress = timers_address; 27 | _values = new uint8_t[_alarmCount + _timerCount]; 28 | _alarms = new AQUA_relayAlarm[_alarmCount]; 29 | _timers = new AQUA_relayTimer[_timerCount]; 30 | _manual = new AQUA_relayManual[_alarmCount + _timerCount]; 31 | 32 | position = 0; 33 | for(i = 0; i < _alarmCount; i++) { 34 | eeprom_busy_wait(); 35 | value = eeprom_read_word((const uint16_t *)(_alarmAddress + position)); 36 | if(value == 0xFFFF) { //address wasn't set yet 37 | _alarms[i].state = 0; 38 | _alarms[i].start = 0; 39 | _alarms[i].stop = 0; 40 | position+= 4; 41 | } else { 42 | _alarms[i].state = (bool)(value & 32768); 43 | if(_alarms[i].state == 1) { 44 | value-= 32768; 45 | } 46 | negative = (bool)(value & 16384); 47 | if(negative == 1) { 48 | value = 0 - (value - 16384); 49 | } 50 | _alarms[i].start = value; 51 | position+= 2; 52 | eeprom_busy_wait(); 53 | value = eeprom_read_word((const uint16_t *)(_alarmAddress + position)); 54 | negative = (bool)(value & 16384); 55 | if(negative == 1) { 56 | value = 0 - (value - 16384); 57 | } 58 | _alarms[i].stop = value; 59 | position+= 2; 60 | } 61 | } 62 | 63 | position = 0; 64 | for(i = 0; i < _timerCount; i++) { 65 | _timers[i].part = new AQUA_relayTimerPart[_timerParts]; 66 | for(j = 0; j < _timerParts; j++) { 67 | eeprom_busy_wait(); 68 | value = eeprom_read_word((const uint16_t *)(_timerAddress + position)); 69 | if(value == 0xFFFF) { //address wasn't set yet 70 | _timers[i].part[j].state = 0; 71 | _timers[i].part[j].from = 0; 72 | _timers[i].part[j].to = 0; 73 | position+= 4; 74 | } else { 75 | _timers[i].part[j].state = (bool)(value & 32768); 76 | if(_timers[i].part[j].state == 1) { 77 | value-= 32768; 78 | } 79 | _timers[i].part[j].from = value; 80 | position+= 2; 81 | eeprom_busy_wait(); 82 | _timers[i].part[j].to = eeprom_read_word((const uint16_t *)(_timerAddress + position)); 83 | position+= 2; 84 | } 85 | } 86 | } 87 | 88 | for(i = 0; i < (_alarmCount + _timerCount); i++) { 89 | _values[i] = AQUA_RELAY_ON; 90 | set(i, AQUA_RELAY_OFF); 91 | pinMode(_firstPin+i, OUTPUT); 92 | _manual[i].manual = 0; 93 | _manual[i].value = AQUA_RELAY_OFF; 94 | } 95 | } 96 | 97 | bool AQUA_relay::get(uint8_t relay) { 98 | bool res = AQUA_RELAY_OFF; 99 | 100 | if(relay < (_alarmCount + _timerCount) && relay >= 0) { 101 | res = _values[relay]; 102 | } 103 | return res; 104 | } 105 | 106 | bool AQUA_relay::set(uint8_t relay, bool value) { 107 | bool res = false; 108 | 109 | if(relay < (_alarmCount + _timerCount) && relay >= 0) { 110 | if(_values[relay] != value) { 111 | _values[relay] = value; 112 | digitalWrite(_firstPin+relay, _values[relay]); 113 | delay(50); 114 | res = true; 115 | } 116 | } 117 | return res; 118 | } 119 | 120 | bool AQUA_relay::getByAlarm(uint8_t relay, int value) { 121 | bool res = AQUA_RELAY_OFF; 122 | 123 | if(relay < _alarmCount && relay >= 0) { 124 | if(_alarms[relay].state == 1) { 125 | if(_alarms[relay].start > _alarms[relay].stop) { 126 | if(_values[relay] == AQUA_RELAY_OFF && value >= _alarms[relay].start) { 127 | res = AQUA_RELAY_ON; 128 | } else if(_values[relay] == AQUA_RELAY_ON && value > _alarms[relay].stop) { 129 | res = AQUA_RELAY_ON; 130 | } 131 | } else if(_alarms[relay].start < _alarms[relay].stop) { 132 | if(_values[relay] == AQUA_RELAY_OFF && value <= _alarms[relay].start) { 133 | res = AQUA_RELAY_ON; 134 | } else if(_values[relay] == AQUA_RELAY_ON && value < _alarms[relay].stop) { 135 | res = AQUA_RELAY_ON; 136 | } 137 | } else { 138 | if(value != _alarms[relay].start) { 139 | res = AQUA_RELAY_ON; 140 | } 141 | } 142 | } 143 | } 144 | return res; 145 | } 146 | 147 | bool AQUA_relay::getByTimer(uint8_t relay, uint16_t tstamp) { 148 | bool res = AQUA_RELAY_OFF; 149 | 150 | if(relay < (_alarmCount + _timerCount) && relay >= _alarmCount) { 151 | relay-= _alarmCount; 152 | for(uint8_t j = 0; j < _timerParts; j++) { 153 | if(_timers[relay].part[j].state == 1) { 154 | if(_timers[relay].part[j].from == _timers[relay].part[j].to) { 155 | res = AQUA_RELAY_ON; 156 | } else if(_timers[relay].part[j].from < _timers[relay].part[j].to) { 157 | if(tstamp >= _timers[relay].part[j].from && tstamp < _timers[relay].part[j].to) { 158 | res = AQUA_RELAY_ON; 159 | } 160 | } else { 161 | if(tstamp >= _timers[relay].part[j].from || tstamp < _timers[relay].part[j].to) { 162 | res = AQUA_RELAY_ON; 163 | } 164 | } 165 | } 166 | } 167 | } 168 | return res; 169 | } 170 | 171 | bool AQUA_relay::isManual(uint8_t relay) { 172 | bool res = false; 173 | 174 | if(relay < (_alarmCount + _timerCount) && relay >= 0) { 175 | res = _manual[relay].manual; 176 | } 177 | return res; 178 | } 179 | 180 | bool AQUA_relay::getByManual(uint8_t relay) { 181 | bool res = AQUA_RELAY_OFF; 182 | 183 | if(relay < (_alarmCount + _timerCount) && relay >= 0) { 184 | if(_manual[relay].manual == 1) { 185 | res = _manual[relay].value; 186 | } else { 187 | res = _values[relay]; 188 | } 189 | } 190 | return res; 191 | } 192 | 193 | bool AQUA_relay::setManual(uint8_t relay, bool manual) { 194 | bool res = false; 195 | 196 | if(relay < (_alarmCount + _timerCount) && relay >= 0) { 197 | _manual[relay].manual = manual; 198 | res = true; 199 | } 200 | return res; 201 | } 202 | 203 | bool AQUA_relay::setManualValue(uint8_t relay, bool value) { 204 | bool res = false; 205 | 206 | if(relay < (_alarmCount + _timerCount) && relay >= 0) { 207 | _manual[relay].value = value; 208 | res = true; 209 | } 210 | return res; 211 | } 212 | 213 | AQUA_relayAlarm AQUA_relay::readRelayAlarm(uint8_t relay) { 214 | AQUA_relayAlarm alarm; 215 | if(relay < _alarmCount && relay >= 0) { 216 | alarm.state = _alarms[relay].state; 217 | alarm.start = _alarms[relay].start; 218 | alarm.stop = _alarms[relay].stop; 219 | } else { 220 | alarm.state = 0; 221 | alarm.start = 0; 222 | alarm.stop = 0; 223 | } 224 | return alarm; 225 | } 226 | 227 | AQUA_relayTimerPart AQUA_relay::readRelayTimerPart(uint8_t relay, uint8_t part) { 228 | AQUA_relayTimerPart timerPart; 229 | if(relay < (_alarmCount + _timerCount) && relay >= _alarmCount && part < _timerParts && part >= 0) { 230 | relay-= _alarmCount; 231 | timerPart.state = _timers[relay].part[part].state; 232 | timerPart.from = _timers[relay].part[part].from; 233 | timerPart.to = _timers[relay].part[part].to; 234 | } else { 235 | timerPart.state = 0; 236 | timerPart.from = 0; 237 | timerPart.to = 0; 238 | } 239 | return timerPart; 240 | } 241 | 242 | bool AQUA_relay::writeRelayAlarm(uint8_t relay, AQUA_relayAlarm *values) { 243 | bool res = false; 244 | 245 | if(relay < _alarmCount && relay >= 0 && values->start < 16384 && values->start > -16384 && values->stop < 16384 && values->stop > -16384) { 246 | if(values->state != _alarms[relay].state || values->start != _alarms[relay].start || values->stop != _alarms[relay].stop) { 247 | _alarms[relay].state = values->state; 248 | _alarms[relay].start = values->start; 249 | _alarms[relay].stop = values->stop; 250 | uint16_t plusValue = 0; 251 | if(_alarms[relay].state == 1) { 252 | plusValue+= 32768; 253 | } 254 | if(_alarms[relay].start < 0) { 255 | plusValue+= 16384; 256 | } 257 | uint16_t position = relay*4; 258 | eeprom_busy_wait(); 259 | eeprom_write_word((uint16_t *)(_alarmAddress + position), abs(_alarms[relay].start) + plusValue); 260 | plusValue = 0; 261 | if(_alarms[relay].stop < 0) { 262 | plusValue+= 16384; 263 | } 264 | position+= 2; 265 | eeprom_busy_wait(); 266 | eeprom_write_word((uint16_t *)(_alarmAddress + position), abs(_alarms[relay].stop) + plusValue); 267 | res = true; 268 | } 269 | } 270 | return res; 271 | } 272 | 273 | bool AQUA_relay::writeRelayTimer(uint8_t relay, uint8_t part, AQUA_relayTimerPart *values) { 274 | bool res = false; 275 | 276 | if(relay < (_alarmCount + _timerCount) && relay >= _alarmCount && part < _timerParts && part >= 0 && values->from < 1440 && values->from >= 0 && values->to < 1440 && values->to >= 0) { 277 | relay-= _alarmCount; 278 | if(values->state != _timers[relay].part[part].state || values->from != _timers[relay].part[part].from || values->to != _timers[relay].part[part].to) { 279 | _timers[relay].part[part].state = values->state; 280 | _timers[relay].part[part].from = values->from; 281 | _timers[relay].part[part].to = values->to; 282 | uint16_t plusValue = 0; 283 | if(_timers[relay].part[part].state == 1) { 284 | plusValue+= 32768; 285 | } 286 | uint16_t position = (relay*_timerParts*4) + (part*4); 287 | eeprom_busy_wait(); 288 | eeprom_write_word((uint16_t *)(_timerAddress + position), _timers[relay].part[part].from + plusValue); 289 | position+= 2; 290 | eeprom_busy_wait(); 291 | eeprom_write_word((uint16_t *)(_timerAddress + position), _timers[relay].part[part].to); 292 | res = true; 293 | } 294 | } 295 | return res; 296 | } 297 | -------------------------------------------------------------------------------- /Arduino/AquariumController/AQUA_relay.h: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Library: Relay 4 | Version: 1.0 5 | Author: Rastislav Birka 6 | */ 7 | 8 | #ifndef AQUA_relay_h 9 | #define AQUA_relay_h 10 | 11 | #define AQUA_RELAY_ON 0 //relay is turn on 12 | #define AQUA_RELAY_OFF 1 //relay is turn off 13 | 14 | typedef struct { 15 | bool manual; 16 | uint8_t value; 17 | } AQUA_relayManual; 18 | 19 | typedef struct { 20 | bool state; 21 | int start; 22 | int stop; 23 | } AQUA_relayAlarm; 24 | 25 | typedef struct { 26 | bool state; 27 | uint16_t from; 28 | uint16_t to; 29 | } AQUA_relayTimerPart; 30 | 31 | typedef struct { 32 | AQUA_relayTimerPart* part; 33 | } AQUA_relayTimer; 34 | 35 | class AQUA_relay { 36 | public: 37 | void init(uint8_t firstPin, uint8_t alarms, uint8_t timers, uint8_t timer_parts, uint8_t alarms_address, uint8_t timers_address); 38 | bool get(uint8_t relay); 39 | bool set(uint8_t relay, bool value); 40 | bool getByAlarm(uint8_t relay, int value); 41 | bool getByTimer(uint8_t relay, uint16_t tstamp); 42 | bool isManual(uint8_t relay); 43 | bool getByManual(uint8_t relay); 44 | bool setManual(uint8_t relay, bool manual); 45 | bool setManualValue(uint8_t relay, bool state); 46 | AQUA_relayAlarm readRelayAlarm(uint8_t relay); 47 | AQUA_relayTimerPart readRelayTimerPart(uint8_t relay, uint8_t part); 48 | bool writeRelayAlarm(uint8_t relay, AQUA_relayAlarm *values); 49 | bool writeRelayTimer(uint8_t relay, uint8_t part, AQUA_relayTimerPart *values); 50 | 51 | private: 52 | uint8_t _firstPin; 53 | uint8_t _alarmCount; 54 | uint8_t _timerCount; 55 | uint8_t _timerParts; 56 | uint8_t _alarmAddress; 57 | uint8_t _timerAddress; 58 | uint8_t* _values; 59 | AQUA_relayAlarm* _alarms; 60 | AQUA_relayTimer* _timers; 61 | AQUA_relayManual* _manual; 62 | }; 63 | #endif 64 | -------------------------------------------------------------------------------- /Arduino/AquariumController/AQUA_temp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Library: Temperature (a 4.7K resistor is necessary) 4 | Version: 1.0 5 | Author: Rastislav Birka 6 | */ 7 | 8 | #include 9 | #include 10 | #include "AQUA_temp.h" 11 | 12 | /* 13 | Public Functions 14 | */ 15 | 16 | void AQUA_temp::init(uint8_t dqPin, uint8_t calibrate_points, uint8_t calibrate_address) { 17 | uint16_t value, position; 18 | uint8_t i; 19 | 20 | _dqPin = dqPin; 21 | _pointCount = calibrate_points; 22 | _calibrateAddress = calibrate_address; 23 | _calData = new AQUA_tempCalibrationPoint[_pointCount]; 24 | _usedData = new AQUA_tempCalibrationPoint[_pointCount]; 25 | _const = new float[(_pointCount - 1)*2]; 26 | 27 | position = 0; 28 | for(i = 0; i < _pointCount; i++) { 29 | eeprom_busy_wait(); 30 | value = eeprom_read_word((const uint16_t *)(_calibrateAddress + position)); 31 | if(value == 0xFFFF) { //address wasn't set yet 32 | _calData[i].state = 0; 33 | _calData[i].refValue = 0; 34 | _calData[i].actValue = 0; 35 | position+= 4; 36 | } else { 37 | _calData[i].state = (bool)(value & 32768); 38 | if(_calData[i].state == 1) { 39 | value-= 32768; 40 | } 41 | _calData[i].refValue = (float)value/100.0; 42 | position+= 2; 43 | eeprom_busy_wait(); 44 | value = eeprom_read_word((const uint16_t *)(_calibrateAddress + position)); 45 | _calData[i].actValue = (float)value/100.0; 46 | position+= 2; 47 | } 48 | } 49 | _setCalibrationValues(); 50 | pinMode(_dqPin, INPUT); 51 | } 52 | 53 | float AQUA_temp::getTemp(bool calibrate) { 54 | uint8_t lowByte, highByte; 55 | int16_t rawTemp; 56 | float res = 0; 57 | 58 | _reset(); 59 | _write(DS18B20_SKIPROM); 60 | _write(DS18B20_CONVERTTEMP); 61 | _wait_to_convert(); 62 | _reset(); 63 | _write(DS18B20_SKIPROM); 64 | _write(DS18B20_RSCRATCHPAD); 65 | lowByte = _read(); 66 | highByte = _read(); 67 | _reset(); 68 | 69 | rawTemp = (((int16_t)highByte) << 8) | lowByte; 70 | res = (float)rawTemp * 0.0625; 71 | if(calibrate == 0) { 72 | if(_usedPoints == 1) { 73 | res+= _const[0]; 74 | } else if(_usedPoints > 1) { 75 | if(res >= _usedData[_usedPoints-1].actValue) { 76 | res = _const[(_usedPoints-2)*2]*res + _const[(_usedPoints-2)*2 + 1]; 77 | } else { 78 | for(uint8_t i = 1; i < _usedPoints; i++) { 79 | if(res <= _usedData[i].actValue) { 80 | res = _const[(i-1)*2]*res + _const[(i-1)*2 + 1]; 81 | break; 82 | } 83 | } 84 | } 85 | } 86 | } 87 | 88 | return res; 89 | } 90 | 91 | bool AQUA_temp::calibration(uint8_t point, AQUA_tempCalibrationPoint *values) { 92 | bool res = false; 93 | 94 | if(point < _pointCount && point >= 0 && values->refValue <= 4999 && values->refValue >= 0 && values->actValue <= 4999 && values->actValue >= 0) { 95 | if(values->state != _calData[point].state || values->refValue != _calData[point].refValue || values->actValue != _calData[point].actValue) { 96 | _calData[point].state = values->state; 97 | _calData[point].refValue = values->refValue; 98 | _calData[point].actValue = values->actValue; 99 | uint16_t plusValue = 0; 100 | if(_calData[point].state == 1) { 101 | plusValue+= 32768; 102 | } 103 | uint16_t position = point*4; 104 | eeprom_busy_wait(); 105 | eeprom_write_word((uint16_t *)(_calibrateAddress + position), _calData[point].refValue*100 + plusValue); 106 | position+= 2; 107 | eeprom_busy_wait(); 108 | eeprom_write_word((uint16_t *)(_calibrateAddress + position), _calData[point].actValue*100); 109 | _setCalibrationValues(); 110 | res = true; 111 | } 112 | } 113 | return res; 114 | } 115 | 116 | AQUA_tempCalibrationPoint AQUA_temp::readCalibrationPoint(uint8_t point) { 117 | AQUA_tempCalibrationPoint calPoint; 118 | if(point < _pointCount && point >= 0) { 119 | calPoint.state = _calData[point].state; 120 | calPoint.refValue = _calData[point].refValue; 121 | calPoint.actValue = _calData[point].actValue; 122 | } else { 123 | calPoint.state = 0; 124 | calPoint.refValue = 0; 125 | calPoint.actValue = 0; 126 | } 127 | return calPoint; 128 | } 129 | 130 | /* 131 | Private Functions 132 | */ 133 | 134 | /* 135 | c1 = (ref2 - ref1)/(act2 - act1) 136 | c2 = ref2 - c1*act2 137 | temp = c1*SensorValue + c2 138 | */ 139 | void AQUA_temp::_setCalibrationValues() { 140 | uint8_t i,j; 141 | bool isCorrect; 142 | 143 | _usedPoints = 0; 144 | for(i = 0; i < _pointCount; i++) { 145 | if(_calData[i].state == 1 && _calData[i].actValue > 0 && _calData[i].refValue > 0) { 146 | if(_usedPoints > 0) { 147 | isCorrect = 1; 148 | for(j = 0; j < _usedPoints; j++) { 149 | if(_calData[i].actValue == _usedData[j].actValue || _calData[i].refValue == _usedData[j].refValue) { 150 | isCorrect = 0; 151 | break; 152 | } 153 | } 154 | if(isCorrect == 1) { 155 | j = _usedPoints; 156 | for(j; j > 0 && _usedData[j-1].actValue > _calData[i].actValue; --j) { 157 | _usedData[j].state = _usedData[j-1].state; 158 | _usedData[j].refValue = _usedData[j-1].refValue; 159 | _usedData[j].actValue = _usedData[j-1].actValue; 160 | } 161 | _usedData[j].state = _calData[i].state; 162 | _usedData[j].refValue = _calData[i].refValue; 163 | _usedData[j].actValue = _calData[i].actValue; 164 | _usedPoints++; 165 | } 166 | } else { 167 | _usedData[_usedPoints].state = _calData[i].state; 168 | _usedData[_usedPoints].refValue = _calData[i].refValue; 169 | _usedData[_usedPoints].actValue = _calData[i].actValue; 170 | _usedPoints++; 171 | } 172 | } 173 | } 174 | if(_usedPoints == 1) { 175 | _const[0] = (_usedData[0].refValue - _usedData[0].actValue); 176 | } else if(_usedPoints > 1) { 177 | for(i = 0; i < _usedPoints - 1; i++) { 178 | _const[i*2] = (_usedData[i+1].refValue - _usedData[i].refValue)/(_usedData[i+1].actValue - _usedData[i].actValue); 179 | _const[i*2 + 1] = _usedData[i+1].refValue - _const[i*2]*_usedData[i+1].actValue; 180 | } 181 | } 182 | } 183 | 184 | bool AQUA_temp::_reset(void) { 185 | bool res; 186 | 187 | noInterrupts(); 188 | digitalWrite(_dqPin, HIGH); 189 | digitalWrite(_dqPin, LOW); 190 | pinMode(_dqPin, OUTPUT); 191 | interrupts(); 192 | delayMicroseconds(480); 193 | noInterrupts(); 194 | pinMode(_dqPin, INPUT); 195 | delayMicroseconds(70); 196 | res = !digitalRead(_dqPin); 197 | interrupts(); 198 | delayMicroseconds(410); 199 | 200 | return res; 201 | } 202 | 203 | uint8_t AQUA_temp::_read(void) { 204 | uint8_t res = 0; 205 | 206 | for(uint8_t bitMask = 0x01; bitMask; bitMask <<= 1) { 207 | if(_read_bit()) { 208 | res |= bitMask; 209 | } 210 | } 211 | return res; 212 | } 213 | 214 | uint8_t AQUA_temp::_read_bit(void) { 215 | uint8_t res; 216 | 217 | noInterrupts(); 218 | pinMode(_dqPin, OUTPUT); 219 | digitalWrite(_dqPin, LOW); 220 | delayMicroseconds(3); 221 | pinMode(_dqPin, INPUT); 222 | // digitalWrite(_dqPin, HIGH); 223 | delayMicroseconds(10); 224 | res = digitalRead(_dqPin); 225 | interrupts(); 226 | delayMicroseconds(53); 227 | 228 | return res; 229 | } 230 | 231 | void AQUA_temp::_write(uint8_t command) { 232 | for(uint8_t bitMask = 0x01; bitMask; bitMask <<= 1) { 233 | _write_bit((bitMask & command)?1:0); 234 | } 235 | /* noInterrupts(); 236 | pinMode(_dqPin, INPUT); 237 | digitalWrite(_dqPin, LOW); 238 | interrupts();*/ 239 | } 240 | 241 | void AQUA_temp::_write_bit(uint8_t value) { 242 | if(value & 1) { 243 | noInterrupts(); 244 | digitalWrite(_dqPin, LOW); 245 | pinMode(_dqPin, OUTPUT); 246 | delayMicroseconds(10); 247 | digitalWrite(_dqPin, HIGH); 248 | interrupts(); 249 | delayMicroseconds(55); 250 | } else { 251 | noInterrupts(); 252 | digitalWrite(_dqPin, LOW); 253 | pinMode(_dqPin, OUTPUT); 254 | delayMicroseconds(65); 255 | digitalWrite(_dqPin, HIGH); 256 | interrupts(); 257 | delayMicroseconds(5); 258 | } 259 | } 260 | 261 | void AQUA_temp::_wait_to_convert(void) { 262 | unsigned long waiting = millis() + 750; 263 | while(millis() < waiting) { 264 | if(digitalRead(_dqPin) > 0) { 265 | break; 266 | } 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /Arduino/AquariumController/AQUA_temp.h: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Library: Temperature (a 4.7K resistor is necessary) 4 | Version: 1.0 5 | Author: Rastislav Birka 6 | */ 7 | 8 | #ifndef AQUA_temp_h 9 | #define AQUA_temp_h 10 | 11 | #define DS18B20_RPWRSUPPLY 0xB4 12 | #define DS18B20_SEARCHROM 0xF0 13 | #define DS18B20_READROM 0x33 14 | #define DS18B20_MATCHROM 0x55 15 | #define DS18B20_SKIPROM 0xCC 16 | #define DS18B20_ALARMSEARCH 0xEC 17 | #define DS18B20_CONVERTTEMP 0x44 18 | #define DS18B20_RSCRATCHPAD 0xBE 19 | #define DS18B20_WSCRATCHPAD 0x4E 20 | #define DS18B20_CPYSCRATCHPAD 0x48 21 | #define DS18B20_RECEEPROM 0xB8 22 | 23 | typedef struct { 24 | bool state; 25 | float refValue; 26 | float actValue; 27 | } AQUA_tempCalibrationPoint; 28 | 29 | class AQUA_temp { 30 | public: 31 | void init(uint8_t dqPin, uint8_t calibrate_points, uint8_t calibrate_address); 32 | float getTemp(bool calibrate = 0); 33 | bool calibration(uint8_t point, AQUA_tempCalibrationPoint *values); 34 | AQUA_tempCalibrationPoint readCalibrationPoint(uint8_t point); 35 | 36 | private: 37 | uint8_t _dqPin; 38 | uint8_t _pointCount; 39 | uint8_t _calibrateAddress; 40 | AQUA_tempCalibrationPoint* _calData; 41 | AQUA_tempCalibrationPoint* _usedData; 42 | uint8_t _usedPoints; 43 | float* _const; 44 | 45 | void _setCalibrationValues(); 46 | bool _reset(void); 47 | uint8_t _read(void); 48 | uint8_t _read_bit(void); 49 | void _write(uint8_t command); 50 | void _write_bit(uint8_t value); 51 | void _wait_to_convert(void); 52 | }; 53 | #endif 54 | -------------------------------------------------------------------------------- /Arduino/AquariumController/AQUA_time.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Library: Time 4 | Version: 1.0 5 | Author: Rastislav Birka 6 | */ 7 | 8 | #include 9 | #include 10 | #include "AQUA_time.h" 11 | 12 | /* 13 | Public Functions 14 | */ 15 | 16 | void AQUA_time::init(uint8_t dataPin, uint8_t clockPin, uint8_t dsType, bool useDST, uint8_t timeZone) { 17 | _dataPin = dataPin; 18 | _clockPin = clockPin; 19 | _dsType = dsType; 20 | _useDST = useDST; 21 | _timeZone = timeZone; 22 | pinMode(_clockPin, OUTPUT); 23 | start(); 24 | } 25 | 26 | void AQUA_time::setOutput(bool enable) { 27 | uint8_t value, addr, bit; 28 | switch(_dsType) { 29 | case DS_TYPE_3231: 30 | addr = TIME_ADDR_CONTROL_3231; 31 | bit = 2; 32 | break; 33 | case DS_TYPE_1307: 34 | default: 35 | addr = TIME_ADDR_CONTROL_1307; 36 | bit = 7; 37 | } 38 | value = _readRegister(addr); 39 | if((value & (1 << bit)) != enable) { 40 | value &= ~(1 << bit); 41 | value |= (enable << bit); 42 | _writeRegister(addr, value); 43 | } 44 | } 45 | 46 | void AQUA_time::enableSQW(bool enable) { 47 | uint8_t value, addr, bit; 48 | switch(_dsType) { 49 | case DS_TYPE_3231: 50 | addr = TIME_ADDR_CONTROL_3231; 51 | bit = 6; 52 | break; 53 | case DS_TYPE_1307: 54 | default: 55 | addr = TIME_ADDR_CONTROL_1307; 56 | bit = 4; 57 | } 58 | value = _readRegister(addr); 59 | if((value & (1 << bit)) != enable) { 60 | value &= ~(1 << bit); 61 | value |= (enable << bit); 62 | _writeRegister(addr, value); 63 | } 64 | } 65 | 66 | void AQUA_time::setSQWRate(int rate) { 67 | uint8_t value, addr, rs; 68 | if(rate > 3) { 69 | rate = 3; 70 | } 71 | switch(_dsType) { 72 | case DS_TYPE_3231: 73 | addr = TIME_ADDR_CONTROL_3231; 74 | rs = 24; //00011000 75 | rate <<= 3; 76 | break; 77 | case DS_TYPE_1307: 78 | default: 79 | addr = TIME_ADDR_CONTROL_1307; 80 | rs = 3; 81 | } 82 | value = _readRegister(addr); 83 | value &= ~(rs); 84 | value |= (rate); 85 | _writeRegister(addr, value); 86 | } 87 | 88 | void AQUA_time::start() { 89 | uint8_t value, addr; 90 | switch(_dsType) { 91 | case DS_TYPE_3231: 92 | addr = TIME_ADDR_CONTROL_3231; 93 | break; 94 | case DS_TYPE_1307: 95 | default: 96 | addr = TIME_ADDR_SEC; 97 | } 98 | value = _readRegister(addr); 99 | if((value & 128) != 0) { 100 | value &= ~(1 << 7); 101 | value |= (0 << 7); 102 | _writeRegister(addr, value); 103 | } 104 | } 105 | 106 | void AQUA_time::stop() { 107 | uint8_t value, addr; 108 | switch(_dsType) { 109 | case DS_TYPE_3231: 110 | addr = TIME_ADDR_CONTROL_3231; 111 | break; 112 | case DS_TYPE_1307: 113 | default: 114 | addr = TIME_ADDR_SEC; 115 | } 116 | value = _readRegister(addr); 117 | if((value & 128) != 1) { 118 | value &= ~(1 << 7); 119 | value |= (1 << 7); 120 | _writeRegister(addr, value); 121 | } 122 | } 123 | 124 | void AQUA_time::setDate(uint8_t day, uint8_t mon, uint16_t year) { 125 | if(day > 0 && day < 32 && mon > 0 && mon < 13 && year > 1999 && year < 2100) { 126 | _writeRegister(TIME_ADDR_YEAR, _encode(year-2000)); 127 | _writeRegister(TIME_ADDR_MON, _encode(mon)); 128 | _writeRegister(TIME_ADDR_DAY, _encode(day)); 129 | _writeRegister(TIME_ADDR_WDAY, _calculateWday(day, mon, year)); 130 | } 131 | } 132 | 133 | void AQUA_time::setTime(uint8_t hour, uint8_t min, uint8_t sec) { 134 | if(hour >= 0 && hour < 24 && min >= 0 && min < 60 && sec >= 0 && sec < 60) { 135 | if (_isDST && hour > 0) { 136 | hour--; 137 | } 138 | _writeRegister(TIME_ADDR_HOUR, _encode(hour)); 139 | _writeRegister(TIME_ADDR_MIN, _encode(min)); 140 | _writeRegister(TIME_ADDR_SEC, _encode(sec)); 141 | } 142 | } 143 | 144 | void AQUA_time::setDST(bool useDST) { 145 | _useDST = useDST; 146 | } 147 | 148 | void AQUA_time::setTimeZone(int timeZone) { 149 | _timeZone = timeZone; 150 | } 151 | 152 | AQUA_datetime AQUA_time::getDateTime() { 153 | AQUA_datetime datetimeStruct; 154 | static uint8_t daysInMonths[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; 155 | 156 | _readDateTime(); 157 | datetimeStruct.sec = _decode(_regDateTime[0]); 158 | datetimeStruct.min = _decode(_regDateTime[1]); 159 | datetimeStruct.hour = _decode(_regDateTime[2]); 160 | datetimeStruct.wday = _regDateTime[3]; 161 | datetimeStruct.day = _decode(_regDateTime[4]); 162 | datetimeStruct.mon = _decode(_regDateTime[5]); 163 | datetimeStruct.year = _decode(_regDateTime[6]) + 2000; 164 | 165 | if(datetimeStruct.sec < 0 || datetimeStruct.sec > 60) { 166 | datetimeStruct.sec = 0; 167 | } 168 | if(datetimeStruct.min < 0 || datetimeStruct.min > 60) { 169 | datetimeStruct.min = 0; 170 | } 171 | if(datetimeStruct.hour < 0 || datetimeStruct.hour > 24) { 172 | datetimeStruct.hour = 0; 173 | } 174 | if(datetimeStruct.wday < 1 || datetimeStruct.wday > 7) { 175 | datetimeStruct.wday = 1; 176 | } 177 | if(datetimeStruct.day < 1 || datetimeStruct.day > 31) { 178 | datetimeStruct.day = 1; 179 | } 180 | if(datetimeStruct.mon < 1 || datetimeStruct.mon > 12) { 181 | datetimeStruct.mon = 1; 182 | } 183 | if(datetimeStruct.year < 2000 || datetimeStruct.year > 2099) { 184 | datetimeStruct.year = 2000; 185 | } 186 | 187 | _isDST = false; 188 | if(_useDST) { 189 | //DST start in last sunday in march about 01:00 GMT and end in last sunday in october about 01:00 GMT 190 | //sunday = 7th day in week according to ISO 8601 191 | if(datetimeStruct.mon > 3 && datetimeStruct.mon < 10) { 192 | _isDST = true; 193 | } else if(datetimeStruct.mon == 3 && datetimeStruct.day > 24) { 194 | if(datetimeStruct.wday == 7) { 195 | if((datetimeStruct.hour - _timeZone) > 0) { 196 | _isDST = true; 197 | } 198 | } else if((31 - datetimeStruct.day + datetimeStruct.wday) <= 7) { 199 | _isDST = true; 200 | } 201 | } else if(datetimeStruct.mon == 10 && datetimeStruct.day < 25) { 202 | _isDST = true; 203 | } else if(datetimeStruct.mon == 10) { 204 | if(datetimeStruct.wday == 7) { 205 | if((datetimeStruct.hour - _timeZone) < 1) { 206 | _isDST = true; 207 | } 208 | } else if((31 - datetimeStruct.day + datetimeStruct.wday) >= 7) { 209 | _isDST = true; 210 | } 211 | } 212 | if(_isDST) { 213 | datetimeStruct.hour++; 214 | } 215 | if(datetimeStruct.mon >= 3 && datetimeStruct.mon <= 10 && datetimeStruct.hour >= 24) { 216 | datetimeStruct.hour-= 24; 217 | datetimeStruct.day++; 218 | if(datetimeStruct.day > daysInMonths[datetimeStruct.mon-1]) { 219 | datetimeStruct.day = 1; 220 | datetimeStruct.mon++; 221 | } 222 | datetimeStruct.wday++; 223 | if(datetimeStruct.wday > 7) { 224 | datetimeStruct.wday = 1; 225 | } 226 | } 227 | } 228 | 229 | return datetimeStruct; 230 | } 231 | 232 | /* 233 | Private Functions 234 | */ 235 | 236 | uint8_t AQUA_time::_calculateWday(uint8_t day, uint8_t mon, uint16_t year) { 237 | static uint8_t monValues[12] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; 238 | uint8_t wDay = 0; 239 | 240 | if (mon < 3) { 241 | year--; 242 | } 243 | wDay = (year + year/4 - year/100 + year/400 + monValues[mon-1] + day) % 7; 244 | if (wDay == 0) { //Sunday = 0, Monday = 1, ... 245 | wDay = 7; //sunday = 7th day in week according to ISO 8601 246 | } 247 | return wDay; 248 | } 249 | 250 | void AQUA_time::_sendStart(uint8_t addr) { 251 | pinMode(_dataPin, OUTPUT); 252 | digitalWrite(_dataPin, HIGH); 253 | digitalWrite(_clockPin, HIGH); 254 | digitalWrite(_dataPin, LOW); 255 | digitalWrite(_clockPin, LOW); 256 | shiftOut(_dataPin, _clockPin, MSBFIRST, addr); 257 | } 258 | 259 | void AQUA_time::_sendStop() { 260 | pinMode(_dataPin, OUTPUT); 261 | digitalWrite(_dataPin, LOW); 262 | digitalWrite(_clockPin, HIGH); 263 | digitalWrite(_dataPin, HIGH); 264 | pinMode(_dataPin, INPUT); 265 | } 266 | 267 | void AQUA_time::_sendAck() { 268 | pinMode(_dataPin, OUTPUT); 269 | digitalWrite(_clockPin, LOW); 270 | digitalWrite(_dataPin, LOW); 271 | digitalWrite(_clockPin, HIGH); 272 | digitalWrite(_clockPin, LOW); 273 | pinMode(_dataPin, INPUT); 274 | } 275 | 276 | void AQUA_time::_sendNack() { 277 | pinMode(_dataPin, OUTPUT); 278 | digitalWrite(_clockPin, LOW); 279 | digitalWrite(_dataPin, HIGH); 280 | digitalWrite(_clockPin, HIGH); 281 | digitalWrite(_clockPin, LOW); 282 | pinMode(_dataPin, INPUT); 283 | } 284 | 285 | void AQUA_time::_waitForAck() { 286 | pinMode(_dataPin, INPUT); 287 | digitalWrite(_clockPin, HIGH); 288 | while(_dataPin == LOW) { 289 | } 290 | digitalWrite(_clockPin, LOW); 291 | } 292 | 293 | uint8_t AQUA_time::_readByte() { 294 | uint8_t value = 0; 295 | uint8_t currentBit; 296 | 297 | pinMode(_dataPin, INPUT); 298 | for(int i = 0; i < 8; ++i) { 299 | digitalWrite(_clockPin, HIGH); 300 | currentBit = digitalRead(_dataPin); 301 | value |= (currentBit << 7-i); 302 | delayMicroseconds(10); 303 | digitalWrite(_clockPin, LOW); 304 | } 305 | return value; 306 | } 307 | 308 | void AQUA_time::_writeByte(uint8_t value) { 309 | pinMode(_dataPin, OUTPUT); 310 | shiftOut(_dataPin, _clockPin, MSBFIRST, value); 311 | } 312 | 313 | uint8_t AQUA_time::_readRegister(uint8_t reg) { 314 | uint8_t value; 315 | 316 | _sendStart(TIME_ADDR_WRITE); 317 | _waitForAck(); 318 | _writeByte(reg); 319 | _waitForAck(); 320 | _sendStop(); 321 | _sendStart(TIME_ADDR_READ); 322 | _waitForAck(); 323 | value = _readByte(); 324 | _sendNack(); 325 | _sendStop(); 326 | 327 | return value; 328 | } 329 | 330 | void AQUA_time::_writeRegister(uint8_t reg, uint8_t value) { 331 | _sendStart(TIME_ADDR_WRITE); 332 | _waitForAck(); 333 | _writeByte(reg); 334 | _waitForAck(); 335 | _writeByte(value); 336 | _waitForAck(); 337 | _sendStop(); 338 | } 339 | 340 | void AQUA_time::_readDateTime() { 341 | _sendStart(TIME_ADDR_WRITE); 342 | _waitForAck(); 343 | _writeByte(0); 344 | _waitForAck(); 345 | _sendStop(); 346 | _sendStart(TIME_ADDR_READ); 347 | _waitForAck(); 348 | 349 | for(int i = 0; i < 8; i++) { 350 | _regDateTime[i] = _readByte(); 351 | if(i < 7) { 352 | _sendAck(); 353 | } else { 354 | _sendNack(); 355 | } 356 | } 357 | _sendStop(); 358 | } 359 | 360 | uint8_t AQUA_time::_decode(uint8_t value) { 361 | uint8_t decoded = (value & 15) + 10 * ((value & (15 << 4)) >> 4); 362 | return decoded; 363 | } 364 | 365 | uint8_t AQUA_time::_encode(uint8_t value) { 366 | uint8_t encoded = ((value / 10) << 4) + (value % 10); 367 | return encoded; 368 | } 369 | -------------------------------------------------------------------------------- /Arduino/AquariumController/AQUA_time.h: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Library: Time (DS3231) 4 | Version: 1.0 5 | Author: Rastislav Birka 6 | */ 7 | 8 | #ifndef AQUA_time_h 9 | #define AQUA_time_h 10 | 11 | #define DS_TYPE_1307 0 12 | #define DS_TYPE_3231 1 13 | 14 | #define TIME_ADDR_READ 0xD1 //slave address for read: 11010001 15 | #define TIME_ADDR_WRITE 0xD0 //slave address for write: 11010000 16 | #define TIME_ADDR_SEC 0x00 17 | #define TIME_ADDR_MIN 0x01 18 | #define TIME_ADDR_HOUR 0x02 19 | #define TIME_ADDR_WDAY 0x03 20 | #define TIME_ADDR_DAY 0x04 21 | #define TIME_ADDR_MON 0x05 22 | #define TIME_ADDR_YEAR 0x06 23 | #define TIME_ADDR_A1_SEC 0x07 24 | #define TIME_ADDR_A1_MIN 0x08 25 | #define TIME_ADDR_A1_HOUR 0x09 26 | #define TIME_ADDR_A1_DYDT 0x0A 27 | #define TIME_ADDR_A2_MIN 0x0B 28 | #define TIME_ADDR_A2_HOUR 0x0C 29 | #define TIME_ADDR_A2_DYDT 0x0D 30 | #define TIME_ADDR_STATUS 0x0F 31 | #define TIME_ADDR_AGING 0x10 32 | #define TIME_ADDR_TEMP_MSB 0x11 33 | #define TIME_ADDR_TEMP_LSB 0x12 34 | 35 | #define TIME_ADDR_CONTROL_1307 0x07 36 | #define TIME_ADDR_CONTROL_3231 0x0E 37 | 38 | typedef struct { 39 | uint8_t sec; 40 | uint8_t min; 41 | uint8_t hour; 42 | uint8_t wday; 43 | uint8_t day; 44 | uint8_t mon; 45 | uint16_t year; 46 | } AQUA_datetime; 47 | 48 | class AQUA_time { 49 | public: 50 | void init(uint8_t dataPin, uint8_t clockPin, uint8_t dsType = DS_TYPE_1307, bool useDST = false, uint8_t timeZone = 0); 51 | void setOutput(bool enable); 52 | void enableSQW(bool enable); 53 | void setSQWRate(int rate); 54 | void start(); 55 | void stop(); 56 | 57 | void setDate(uint8_t day, uint8_t mon, uint16_t year); 58 | void setTime(uint8_t hour, uint8_t min, uint8_t sec); 59 | void setDST(bool useDST); 60 | void setTimeZone(int timeZone); 61 | AQUA_datetime getDateTime(); 62 | 63 | private: 64 | uint8_t _dataPin, _clockPin, _dsType; 65 | uint8_t _regDateTime[8]; 66 | bool _useDST; //whether will used DST or no 67 | uint8_t _timeZone; //it is used only for calculating DST and only for time zone >= 0 68 | bool _isDST; //actually is DST or no 69 | 70 | uint8_t _calculateWday(uint8_t day, uint8_t mon, uint16_t year); 71 | void _sendStart(uint8_t addr); 72 | void _sendStop(); 73 | void _sendAck(); 74 | void _sendNack(); 75 | void _waitForAck(); 76 | uint8_t _readByte(); 77 | void _writeByte(uint8_t value); 78 | uint8_t _readRegister(uint8_t reg); 79 | void _writeRegister(uint8_t reg, uint8_t value); 80 | void _readDateTime(); 81 | uint8_t _decode(uint8_t value); 82 | uint8_t _encode(uint8_t value); 83 | }; 84 | #endif 85 | -------------------------------------------------------------------------------- /Arduino/AquariumController/AquariumController.h: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Library: Constants 4 | Version: 2.1 5 | Author: Rastislav Birka 6 | */ 7 | 8 | #define AQUA_DEBUG_MODE_ON 0 //0-live application, 1-debug mode with print to serial 9 | #define AQUA_ACTIVITY_LED 12 //pin where is led for indicate activity 10 | #define AQUA_WAKEUP_BUTTON 2 //pin where is button for wakeup 11 | #define AQUA_ANALOG_VREF 3300 //reference voltage for analog (mV) 12 | #define AQUA_ADC_BIT_RESOLUTION 10 //ADC bit resolution (10 for arduino internal ADC) 13 | 14 | #define AQUA_RELAY_FIRST_PIN 30 //for 8 relay module will use next 7 pins (30,...,37) 15 | #define AQUA_RELAY_ALARMS 4 //number of alarms (temperature high, temperature low, pH high, pH low) 16 | #define AQUA_RELAY_TIMERS 4 //number of timers (day light, night light, ...) 17 | #define AQUA_RELAY_TIMER_PARTS 4 //number of timer parts (day light, night light, ...) 18 | #define AQUA_RELAY_ALARMS_ADDR 0x00 //4 bytes for each alarm = 2 bytes for start value and 2 bytes for stop value (4 alarms = 16 bytes) 19 | #define AQUA_RELAY_TIMERS_ADDR 0x10 //4 bytes for each timer part = 2 bytes for start timestamp and 2 bytes for end timestamp (4 timer parts for each timer = 16 timer parts = 64 bytes) 20 | 21 | #define AQUA_TIME_DATA_PIN 22 //SDA pin 22 | #define AQUA_TIME_CLOCK_PIN 23 //SCLK pin 23 | #define AQUA_TIME_SQ_PIN 24 //SQ pin 24 | #define AQUA_TIME_DS_PIN 25 //DS pin 25 | 26 | #define AQUA_TEMP_DQ_PIN 26 //DQ pin 27 | #define AQUA_TEMP_CALIBRATE_ADDR 0x50 //4 bytes for each calibration point = 2 bytes for reference value and 2 bytes for measured value (3 point calibration = 12 bytes) 28 | #define AQUA_TEMP_CALIBRATE_POINTS 3 //number of calibrating points 29 | #define AQUA_TEMP_RELAY_COOLING 0 //cooling 30 | #define AQUA_TEMP_RELAY_HEATING 1 //heating 31 | 32 | #define AQUA_PH_DQ_PIN 27 //DQ pin 33 | #define AQUA_PH_CALIBRATE_ADDR 0x60 //4 bytes for each calibration point = 2 bytes for reference value and 2 bytes for measured value (3 point calibration = 12 bytes) 34 | #define AQUA_PH_CALIBRATE_POINTS 3 //number of calibrating points 35 | #define AQUA_PH_RELAY_REDUCTION 2 //pH reduction 36 | #define AQUA_PH_RELAY_INCREASE 3 //pH increase 37 | #define AQUA_PH_VOUT_PIN 0 //VOUT pin - Analog Output 38 | #define AQUA_PH_VOCM_PIN 1 //VOCM pin - Output common mode voltage 39 | 40 | #define AQUA_ORP_DQ_PIN 28 //DQ pin 41 | #define AQUA_ORP_CALIBRATE_ADDR 0x70 //4 bytes for each calibration point = 2 bytes for reference value and 2 bytes for measured value (3 point calibration = 12 bytes) 42 | #define AQUA_ORP_CALIBRATE_POINTS 3 //number of calibrating points 43 | #define AQUA_ORP_VOUT_PIN 4 //VOUT pin - Analog Output 44 | #define AQUA_ORP_VOCM_PIN 5 //VOCM pin - Output common mode voltage 45 | 46 | #define AQUA_LCD_DEFAULT_TIMEOUT 30 //timeout for display sleep mode in seconds 47 | #define AQUA_LCD_TIMEOUT_ADDR 0x80 //2 bytes for lcd timeout in seconds 48 | #define AQUA_LCD_SERIAL 2 //which serial port is used for LCD //1 = pin 19(RX) and pin 18(TX), 2 = pin 17(RX) and pin 16(TX), 3 = pin 15(RX) and pin 14(TX) 49 | #define AQUA_LCD_SERIAL_SPEED 115200 //speed for serial communication 50 | #define AQUA_LCD_RESET_PIN 4 //pin for reset 51 | 52 | #define AQUA_SPI_MISO_PIN 50 //SPI MISO pin 53 | #define AQUA_SPI_MOSI_PIN 51 //SPI MOSI pin 54 | #define AQUA_SPI_SCLK_PIN 52 //SPI SCLK pin 55 | #define AQUA_SPI_SS_PIN 53 //SPI SS pin 56 | #define AQUA_SPI_PH_VOUT_PIN 49 //pH VOUT pin (ADC141S626) 57 | #define AQUA_SPI_ORP_VOUT_PIN 48 //ORP VOUT pin (ADC141S626) 58 | 59 | #define AQUA_ADS1115_SDA_PIN 46 //SDA pin 60 | #define AQUA_ADS1115_SCL_PIN 47 //SCL pin 61 | -------------------------------------------------------------------------------- /Arduino/AquariumController/AquariumController.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Project: Aquarium Controller 3 | Version: 2.1 4 | Author: Rastislav Birka 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "AquariumController.h" 13 | #include "AQUA_relay.h" 14 | #include "AQUA_time.h" 15 | #include "AQUA_temp.h" 16 | #include "AQUA_ph.h" 17 | #include "AQUA_orp.h" 18 | #include "AQUA_lcd.h" 19 | 20 | AQUA_temp objTEMP; 21 | AQUA_ph objPH; 22 | AQUA_orp objORP; 23 | AQUA_time objTIME; 24 | AQUA_relay objRELAY; 25 | AQUA_lcd objLCD; 26 | Genie objGenie; 27 | 28 | static uint8_t relayCount = AQUA_RELAY_ALARMS + AQUA_RELAY_TIMERS; 29 | bool wakeup, wakeupButton, wakeupLCD; 30 | unsigned long inactivity = 0, calWV = 0; 31 | String keyboardString; 32 | bool keyboardStart = true; 33 | AQUA_datetime settingsDatetime; 34 | uint16_t settingsTimeout; 35 | uint8_t settingsRelay; 36 | uint8_t calibration = GENIE_CALIBRATION_OFF; 37 | AQUA_relayAlarm settingsAlarm; 38 | AQUA_relayTimerPart settingsTimer[AQUA_RELAY_TIMER_PARTS]; 39 | AQUA_tempCalibrationPoint tempCalPoint[AQUA_TEMP_CALIBRATE_POINTS]; 40 | AQUA_phCalibrationPoint phCalPoint[AQUA_PH_CALIBRATE_POINTS]; 41 | AQUA_orpCalibrationPoint orpCalPoint[AQUA_ORP_CALIBRATE_POINTS]; 42 | 43 | /*** setup Watchdog Timer ***/ 44 | void setupWDT() { 45 | MCUSR &= ~(1< 0) { //manual control 287 | bool value = objRELAY.get(Event.reportObject.index); 288 | objRELAY.setManualValue(Event.reportObject.index, value); 289 | objGenie.WriteObject(GENIE_OBJ_4DBUTTON, Event.reportObject.index+relayCount, (value == AQUA_RELAY_OFF ? AQUA_RELAY_ON : AQUA_RELAY_OFF)); 290 | } else { //auto control 291 | objRELAY.setManualValue(Event.reportObject.index, AQUA_RELAY_OFF); 292 | objGenie.WriteObject(GENIE_OBJ_4DBUTTON, Event.reportObject.index+relayCount, AQUA_RELAY_ON); 293 | } 294 | } else if(Event.reportObject.index >= relayCount && Event.reportObject.index < (relayCount*2)) { //turn on/off relay buttons 295 | objRELAY.setManualValue(Event.reportObject.index-relayCount, (Event.reportObject.data_lsb == AQUA_RELAY_OFF ? AQUA_RELAY_ON : AQUA_RELAY_OFF)); 296 | } else if(Event.reportObject.index == GENIE_BTN_ALARM_STATE) { //turn on/off alarm button 297 | settingsAlarm.state = Event.reportObject.data_lsb; 298 | } else if(Event.reportObject.index >= GENIE_BTN_TIMER1_STATE && Event.reportObject.index <= GENIE_BTN_TIMER4_STATE) { //turn on/off timer buttons 299 | settingsTimer[Event.reportObject.index - GENIE_BTN_TIMER1_STATE].state = Event.reportObject.data_lsb; 300 | } else if(Event.reportObject.index >= GENIE_BTN_CAL1_STATE && Event.reportObject.index <= GENIE_BTN_CAL3_STATE) { //turn on/off calibration buttons 301 | if(calibration == GENIE_CALIBRATION_TEMP) { 302 | tempCalPoint[Event.reportObject.index - GENIE_BTN_CAL1_STATE].state = Event.reportObject.data_lsb; 303 | } else if(calibration == GENIE_CALIBRATION_PH) { 304 | phCalPoint[Event.reportObject.index - GENIE_BTN_CAL1_STATE].state = Event.reportObject.data_lsb; 305 | } else if(calibration == GENIE_CALIBRATION_ORP) { 306 | orpCalPoint[Event.reportObject.index - GENIE_BTN_CAL1_STATE].state = Event.reportObject.data_lsb; 307 | } 308 | } 309 | } else if(Event.reportObject.object == GENIE_OBJ_WINBUTTON) { 310 | if(Event.reportObject.index == GENIE_BTN_SLEEP) { 311 | displayForm(GENIE_FORM_SLEEP); 312 | } else { 313 | if(Event.reportObject.index == GENIE_BTN_SET_TIME) { 314 | displayForm(GENIE_FORM_SET_TIME); 315 | } else if(Event.reportObject.index >= GENIE_BTN_CALIBRATION_TEMP && Event.reportObject.index <= GENIE_BTN_CALIBRATION_ORP) { //Calibration 316 | /*if((Event.reportObject.index == GENIE_BTN_CALIBRATION_TEMP && objTEMP.getTemp() > 0) 317 | || (Event.reportObject.index == GENIE_BTN_CALIBRATION_PH && objPH.getPH() > 0) 318 | || (Event.reportObject.index == GENIE_BTN_CALIBRATION_ORP && objORP.getORP() != 0))*/ { 319 | displayForm(GENIE_FORM_CALIBRATION, Event.reportObject.index); 320 | } 321 | } else if(Event.reportObject.index >= GENIE_BTN_SET_R1 && Event.reportObject.index <= GENIE_BTN_SET_R4) { //Alarm settings 322 | displayForm(GENIE_FORM_SET_ALARM, Event.reportObject.index); 323 | } else if(Event.reportObject.index >= GENIE_BTN_SET_R5 && Event.reportObject.index <= GENIE_BTN_SET_R8) { //Timer settings 324 | displayForm(GENIE_FORM_SET_TIMER, Event.reportObject.index); 325 | } else if(Event.reportObject.index >= GENIE_BTN_BACK_TIME && Event.reportObject.index <= GENIE_BTN_BACK_CALIBRATION) { //Back buttons 326 | displayForm(GENIE_FORM_MAIN); 327 | } else if(Event.reportObject.index >= GENIE_BTN_SET_DAY && Event.reportObject.index <= GENIE_BTN_SET_TIMEOUT) { //Time settings - "Set" buttons 328 | keyboardStart = true; 329 | iValue = keyboardString.toInt(); 330 | if(Event.reportObject.index == GENIE_BTN_SET_DAY) { 331 | if(iValue < 0) { 332 | iValue = 0; 333 | } else if(iValue > 31) { 334 | iValue = 31; 335 | } 336 | sprintf(row, "%4d\0", iValue); 337 | settingsDatetime.day = iValue; 338 | objGenie.WriteStr(GENIE_STR_DAY, row); 339 | } else if(Event.reportObject.index == GENIE_BTN_SET_MONTH) { 340 | if(iValue < 0) { 341 | iValue = 0; 342 | } else if(iValue > 12) { 343 | iValue = 12; 344 | } 345 | sprintf(row, "%4d\0", iValue); 346 | settingsDatetime.mon = iValue; 347 | objGenie.WriteStr(GENIE_STR_MONTH, row); 348 | } else if(Event.reportObject.index == GENIE_BTN_SET_YEAR) { 349 | if(iValue < 100) { 350 | iValue+= 2000; 351 | } else if(iValue < 2000) { 352 | iValue = 2000; 353 | } else if(iValue > 2099) { 354 | iValue = 2099; 355 | } 356 | sprintf(row, "%4d\0", iValue); 357 | settingsDatetime.year = iValue; 358 | objGenie.WriteStr(GENIE_STR_YEAR, row); 359 | } else if(Event.reportObject.index == GENIE_BTN_SET_HOUR) { 360 | if(iValue < 0) { 361 | iValue = 0; 362 | } else if(iValue > 23) { 363 | iValue = 23; 364 | } 365 | sprintf(row, "%4d\0", iValue); 366 | settingsDatetime.hour = iValue; 367 | objGenie.WriteStr(GENIE_STR_HOUR, row); 368 | } else if(Event.reportObject.index == GENIE_BTN_SET_MIN) { 369 | if(iValue < 0) { 370 | iValue = 0; 371 | } else if(iValue > 59) { 372 | iValue = 59; 373 | } 374 | sprintf(row, "%4d\0", iValue); 375 | settingsDatetime.min = iValue; 376 | objGenie.WriteStr(GENIE_STR_MIN, row); 377 | } else if(Event.reportObject.index == GENIE_BTN_SET_TIMEOUT) { 378 | if(iValue < 0) { 379 | iValue = 0; 380 | } else if(iValue > 3600) { 381 | iValue = 3600; //sleep timeout max 1 hour 382 | } 383 | sprintf(row, "%4d\0", iValue); 384 | settingsTimeout = iValue; 385 | objGenie.WriteStr(GENIE_STR_SLEEP_TIMEOUT, row); 386 | } 387 | } else if(Event.reportObject.index >= GENIE_BTN_SAVE_DATE && Event.reportObject.index <= GENIE_BTN_SAVE_TIMEOUT) { //Time settings - "Save" buttons 388 | if(Event.reportObject.index == GENIE_BTN_SAVE_DATE) { 389 | objTIME.setDate(settingsDatetime.day, settingsDatetime.mon, settingsDatetime.year); 390 | } else if(Event.reportObject.index == GENIE_BTN_SAVE_TIME) { 391 | objTIME.setTime(settingsDatetime.hour, settingsDatetime.min, 0); 392 | } else if(Event.reportObject.index == GENIE_BTN_SAVE_TIMEOUT) { 393 | objLCD.setTimeout(settingsTimeout); 394 | } 395 | objGenie.WriteObject(GENIE_OBJ_STRINGS, GENIE_STR_INFO_TIME, Event.reportObject.index - GENIE_BTN_SET_TIMEOUT); 396 | } else if(Event.reportObject.index >= GENIE_BTN_ALARM_SET_START && Event.reportObject.index <= GENIE_BTN_ALARM_SET_STOP) { //Alarm settings - "Set" buttons 397 | keyboardStart = true; 398 | int iPos = keyboardString.indexOf('.'); 399 | if(iPos > -1) { 400 | iValue = keyboardString.substring(iPos+1, iPos+3).toInt(); 401 | if(iValue > 0 && keyboardString.substring(iPos+1, iPos+3).length() == 1) { 402 | iValue*= 10; 403 | } 404 | iValue+= (keyboardString.substring(0, iPos).toInt()*100); 405 | } else { 406 | iValue = keyboardString.toInt()*100; 407 | } 408 | if(iValue < 0) { 409 | iValue = 0; 410 | } else if(iValue > 4999) { 411 | iValue = 4999; //49.99 412 | } 413 | sprintf(row, "%2d.%02d\0", (int)(iValue/100), iValue%100); 414 | if(Event.reportObject.index == GENIE_BTN_ALARM_SET_START) { 415 | settingsAlarm.start = iValue; 416 | objGenie.WriteStr(GENIE_STR_ALARM_START, row); 417 | } else if(Event.reportObject.index == GENIE_BTN_ALARM_SET_STOP) { 418 | settingsAlarm.stop = iValue; 419 | objGenie.WriteStr(GENIE_STR_ALARM_STOP, row); 420 | } 421 | } else if(Event.reportObject.index == GENIE_BTN_SAVE_ALARM) { //Alarm settings - "Save" button 422 | objRELAY.writeRelayAlarm(settingsRelay, &settingsAlarm); 423 | objGenie.WriteObject(GENIE_OBJ_STRINGS, GENIE_STR_INFO_ALARM, 1); 424 | } else if(Event.reportObject.index >= GENIE_BTN_TIMER1_SET_START && Event.reportObject.index <= GENIE_BTN_TIMER4_SET_STOP) { //Timer settings - "Set" buttons 425 | keyboardStart = true; 426 | int iPos = keyboardString.indexOf(':'); 427 | if(iPos > -1) { 428 | iValue = keyboardString.substring(0, iPos).toInt()*60 + keyboardString.substring(iPos+1, iPos+3).toInt(); 429 | } else { 430 | iValue = keyboardString.toInt(); 431 | if(iValue < 24) { 432 | iValue*= 60; 433 | } 434 | } 435 | if(iValue < 0) { 436 | iValue = 0; 437 | } else if(iValue > 1439) { 438 | iValue = 1439; //23:59 439 | } 440 | sprintf(row, "%2d:%02d\0", (int)(iValue/60), iValue%60); 441 | if(Event.reportObject.index == GENIE_BTN_TIMER1_SET_START) { 442 | settingsTimer[0].from = iValue; 443 | objGenie.WriteStr(GENIE_STR_TIMER1_START, row); 444 | } else if(Event.reportObject.index == GENIE_BTN_TIMER1_SET_STOP) { 445 | settingsTimer[0].to = iValue; 446 | objGenie.WriteStr(GENIE_STR_TIMER1_STOP, row); 447 | } else if(Event.reportObject.index == GENIE_BTN_TIMER2_SET_START) { 448 | settingsTimer[1].from = iValue; 449 | objGenie.WriteStr(GENIE_STR_TIMER2_START, row); 450 | } else if(Event.reportObject.index == GENIE_BTN_TIMER2_SET_STOP) { 451 | settingsTimer[1].to = iValue; 452 | objGenie.WriteStr(GENIE_STR_TIMER2_STOP, row); 453 | } else if(Event.reportObject.index == GENIE_BTN_TIMER3_SET_START) { 454 | settingsTimer[2].from = iValue; 455 | objGenie.WriteStr(GENIE_STR_TIMER3_START, row); 456 | } else if(Event.reportObject.index == GENIE_BTN_TIMER3_SET_STOP) { 457 | settingsTimer[2].to = iValue; 458 | objGenie.WriteStr(GENIE_STR_TIMER3_STOP, row); 459 | } else if(Event.reportObject.index == GENIE_BTN_TIMER4_SET_START) { 460 | settingsTimer[3].from = iValue; 461 | objGenie.WriteStr(GENIE_STR_TIMER4_START, row); 462 | } else if(Event.reportObject.index == GENIE_BTN_TIMER4_SET_STOP) { 463 | settingsTimer[3].to = iValue; 464 | objGenie.WriteStr(GENIE_STR_TIMER4_STOP, row); 465 | } 466 | } else if(Event.reportObject.index >= GENIE_BTN_SAVE_TIMER1 && Event.reportObject.index <= GENIE_BTN_SAVE_TIMER4) { //Timer settings - "Save" buttons 467 | objRELAY.writeRelayTimer(settingsRelay, Event.reportObject.index - GENIE_BTN_SAVE_TIMER1, &settingsTimer[Event.reportObject.index - GENIE_BTN_SAVE_TIMER1]); 468 | objGenie.WriteObject(GENIE_OBJ_STRINGS, GENIE_STR_INFO_TIMER, Event.reportObject.index - GENIE_BTN_TIMER4_SET_STOP); 469 | } else if(Event.reportObject.index >= GENIE_BTN_CAL1_SET_REF && Event.reportObject.index <= GENIE_BTN_CAL3_SET_REF) { //Calibration - "Set" buttons 470 | keyboardStart = true; 471 | int iPos = keyboardString.indexOf('.'); 472 | if(calibration == GENIE_CALIBRATION_ORP) { 473 | iValue = keyboardString.toInt(); 474 | } else if(iPos > -1) { 475 | iValue = keyboardString.substring(iPos+1, iPos+3).toInt(); 476 | if(iValue > 0 && keyboardString.substring(iPos+1, iPos+3).length() == 1) { 477 | iValue*= 10; 478 | } 479 | iValue+= (keyboardString.substring(0, iPos).toInt()*100); 480 | } else { 481 | iValue = keyboardString.toInt()*100; 482 | } 483 | if(calibration == GENIE_CALIBRATION_TEMP) { 484 | if(iValue < 0) { 485 | iValue = 0; 486 | } else if(iValue > 4999) { 487 | iValue = 4999; //temerature 49.99°C 488 | } 489 | tempCalPoint[Event.reportObject.index - GENIE_BTN_CAL1_SET_REF].refValue = (float)iValue/100.00; 490 | sprintf(row, "%2d.%02d\0", (int)tempCalPoint[Event.reportObject.index - GENIE_BTN_CAL1_SET_REF].refValue, (int)(tempCalPoint[Event.reportObject.index - GENIE_BTN_CAL1_SET_REF].refValue*100)%100); 491 | } else if(calibration == GENIE_CALIBRATION_PH) { 492 | if(iValue < 0) { 493 | iValue = 0; 494 | } else if(iValue > 1400) { 495 | iValue = 1400; //pH 14.00 496 | } 497 | phCalPoint[Event.reportObject.index - GENIE_BTN_CAL1_SET_REF].refValue = (float)iValue/100.00; 498 | sprintf(row, "%2d.%02d\0", (int)phCalPoint[Event.reportObject.index - GENIE_BTN_CAL1_SET_REF].refValue, (int)(phCalPoint[Event.reportObject.index - GENIE_BTN_CAL1_SET_REF].refValue*100)%100); 499 | } else if(calibration == GENIE_CALIBRATION_ORP) { 500 | if(iValue < -1999) { 501 | iValue = -1999; 502 | } else if(iValue > 1999) { 503 | iValue = 1999; 504 | } 505 | orpCalPoint[Event.reportObject.index - GENIE_BTN_CAL1_SET_REF].refValue = iValue; 506 | sprintf(row, "%+5d\0", orpCalPoint[Event.reportObject.index - GENIE_BTN_CAL1_SET_REF].refValue); 507 | } 508 | if(Event.reportObject.index == GENIE_BTN_CAL1_SET_REF) { 509 | objGenie.WriteStr(GENIE_STR_CAl1_REF_NEW, row); 510 | } else if(Event.reportObject.index == GENIE_BTN_CAL2_SET_REF) { 511 | objGenie.WriteStr(GENIE_STR_CAl2_REF_NEW, row); 512 | } else if(Event.reportObject.index == GENIE_BTN_CAL3_SET_REF) { 513 | objGenie.WriteStr(GENIE_STR_CAl3_REF_NEW, row); 514 | } 515 | } else if(Event.reportObject.index >= GENIE_BTN_CAL1_READ_ACT && Event.reportObject.index <= GENIE_BTN_CAL3_READ_ACT) { //Calibration - "Read" buttons 516 | displayForm(GENIE_FORM_CALIBRATION_SHOW, Event.reportObject.index); 517 | } else if(Event.reportObject.index == GENIE_BTN_SAVE_CALIBRATION) { //Calibration - "Save" button 518 | if(calibration == GENIE_CALIBRATION_TEMP) { 519 | for(uint8_t i = 0; i < AQUA_TEMP_CALIBRATE_POINTS; i++) { 520 | objTEMP.calibration(i, &tempCalPoint[i]); 521 | } 522 | } else if(calibration == GENIE_CALIBRATION_PH) { 523 | for(uint8_t i = 0; i < AQUA_PH_CALIBRATE_POINTS; i++) { 524 | objPH.calibration(i, &phCalPoint[i]); 525 | } 526 | } else if(calibration == GENIE_CALIBRATION_ORP) { 527 | for(uint8_t i = 0; i < AQUA_ORP_CALIBRATE_POINTS; i++) { 528 | objORP.calibration(i, &orpCalPoint[i]); 529 | } 530 | } 531 | objGenie.WriteObject(GENIE_OBJ_STRINGS, GENIE_STR_INFO_CALIBRATION, 1); 532 | } 533 | } 534 | } else if(Event.reportObject.object == GENIE_OBJ_USERBUTTON) { 535 | if(Event.reportObject.index == GENIE_BTN_WAKEUP) { 536 | displayForm(GENIE_FORM_MAIN); 537 | objGenie.WriteContrast(1); 538 | } 539 | } else if(Event.reportObject.object == GENIE_OBJ_KEYBOARD) { 540 | uint8_t keyboardValue = objGenie.GetEventData(&Event); 541 | if(keyboardValue == GENIE_KEYBOARD_CLEAR_KEY) { 542 | keyboardStart = true; 543 | sprintf(row, "%5d\0", 0); 544 | if(Event.reportObject.index == GENIE_KEYBOARD_TIME) { 545 | objGenie.WriteStr(GENIE_STR_TIME_KEY, row); 546 | } else if(Event.reportObject.index == GENIE_KEYBOARD_ALARM) { 547 | objGenie.WriteStr(GENIE_STR_ALARM_KEY, row); 548 | } else if(Event.reportObject.index == GENIE_KEYBOARD_TIMER) { 549 | objGenie.WriteStr(GENIE_STR_TIMER_KEY, row); 550 | } else if(Event.reportObject.index == GENIE_KEYBOARD_CALIBRATION) { 551 | objGenie.WriteStr(GENIE_STR_CAL_KEY, row); 552 | } 553 | } else { 554 | if(keyboardStart) { 555 | keyboardStart = false; 556 | keyboardString = ""; 557 | } 558 | if((Event.reportObject.index > GENIE_KEYBOARD_TIME && keyboardString.length() < 5) || (Event.reportObject.index == GENIE_KEYBOARD_TIME && keyboardString.length() < 4)) { 559 | keyboardString += char(keyboardValue); 560 | } 561 | char tmp[6]; 562 | keyboardString.toCharArray(tmp, 6); 563 | sprintf(row, "%5s\0", tmp); 564 | if(Event.reportObject.index == GENIE_KEYBOARD_TIME) { 565 | objGenie.WriteStr(GENIE_STR_TIME_KEY, row); 566 | } else if(Event.reportObject.index == GENIE_KEYBOARD_ALARM) { 567 | objGenie.WriteStr(GENIE_STR_ALARM_KEY, row); 568 | } else if(Event.reportObject.index == GENIE_KEYBOARD_TIMER) { 569 | objGenie.WriteStr(GENIE_STR_TIMER_KEY, row); 570 | } else if(Event.reportObject.index == GENIE_KEYBOARD_CALIBRATION) { 571 | objGenie.WriteStr(GENIE_STR_CAL_KEY, row); 572 | } 573 | } 574 | } 575 | } 576 | } 577 | 578 | /*** write actual value into calibration screen ***/ 579 | void writeActualValue() { 580 | char row[8]; 581 | if(calibration == GENIE_CALIBRATION_TEMP) { 582 | float temp = objTEMP.getTemp(1); 583 | sprintf(row, "%2d.%02d\0", (int)temp, (int)(temp*100)%100); 584 | } else if(calibration == GENIE_CALIBRATION_PH) { 585 | float pH = objPH.getPH(1); 586 | sprintf(row, "%2d.%02d\0", (int)pH, (int)(pH*100)%100); 587 | } else if(calibration == GENIE_CALIBRATION_ORP) { 588 | sprintf(row, "%+5d\0", objORP.getORP(1)); 589 | } 590 | objGenie.WriteStr(GENIE_STR_ACTUAL_VALUE, row); 591 | } 592 | 593 | /*** check all what need and set all what need ;-) ***/ 594 | void checkAll() { 595 | AQUA_datetime datetimeStruct = objTIME.getDateTime(); 596 | float temp = objTEMP.getTemp(); 597 | float pH = objPH.getPH(); 598 | int orp = objORP.getORP(); 599 | 600 | checkRelay(datetimeStruct.hour*60 + datetimeStruct.min, temp, pH); 601 | if(wakeupLCD == 1 && objLCD.getActualForm() == GENIE_FORM_MAIN) { 602 | printStatusToLCD(&datetimeStruct, temp, pH, orp); 603 | } 604 | if(AQUA_DEBUG_MODE_ON == 1) { 605 | printStatusToSerial(&datetimeStruct, temp, pH, orp); 606 | } 607 | 608 | if(wakeupLCD == 1 && objLCD.getActualForm() == GENIE_FORM_MAIN && (millis() - inactivity)/1000 > (objLCD.getTimeout())) { 609 | displayForm(GENIE_FORM_SLEEP); 610 | } 611 | } 612 | 613 | /*** set relays to correct status ***/ 614 | void checkRelay(uint16_t tstamp, float temp, float pH) { 615 | bool relayStatus; 616 | uint8_t i; 617 | 618 | for(i = 0; i < relayCount; i++) { 619 | if(objRELAY.isManual(i)) { 620 | relayStatus = objRELAY.getByManual(i); 621 | } else if(i == AQUA_TEMP_RELAY_COOLING || i == AQUA_TEMP_RELAY_HEATING) { 622 | relayStatus = objRELAY.getByAlarm(i, round(temp*100)); 623 | } else if(i == AQUA_PH_RELAY_REDUCTION || i == AQUA_PH_RELAY_INCREASE) { 624 | relayStatus = objRELAY.getByAlarm(i, round(pH*100)); 625 | } else if(i >= AQUA_RELAY_ALARMS) { 626 | relayStatus = objRELAY.getByTimer(i, tstamp); 627 | } else { 628 | relayStatus = objRELAY.get(i); 629 | } 630 | if(relayStatus != objRELAY.get(i)) { 631 | objRELAY.set(i, relayStatus); 632 | } 633 | } 634 | } 635 | 636 | /*** print status to LCD ***/ 637 | void printStatusToLCD(AQUA_datetime *datetimeStruct, float temp, float pH, int orp) { 638 | char row[24]; 639 | if(datetimeStruct->day > 0) { 640 | sprintf(row, "%02d.%02d.%4d %02d:%02d:%02d (%01d)\0", datetimeStruct->day, datetimeStruct->mon, datetimeStruct->year, datetimeStruct->hour, datetimeStruct->min, datetimeStruct->sec, datetimeStruct->wday); 641 | objGenie.WriteStr(GENIE_STR_TIME, row); 642 | } else { 643 | objGenie.WriteStr(GENIE_STR_TIME, "OFF"); 644 | } 645 | if(temp > 0) { 646 | sprintf(row, "%2d.%02d\0", (int)temp, (int)(temp*100)%100); 647 | objGenie.WriteStr(GENIE_STR_TEMP, row); 648 | } else { 649 | objGenie.WriteStr(GENIE_STR_TEMP, "OFF"); 650 | } 651 | if(pH > 0) { 652 | sprintf(row, "%2d.%02d\0", (int)pH, (int)(pH*100)%100); 653 | objGenie.WriteStr(GENIE_STR_PH, row); 654 | } else { 655 | objGenie.WriteStr(GENIE_STR_PH, "OFF"); 656 | } 657 | if(orp != 0) { 658 | sprintf(row, "%+5d\0", orp); 659 | objGenie.WriteStr(GENIE_STR_ORP, row); 660 | } else { 661 | objGenie.WriteStr(GENIE_STR_ORP, "OFF"); 662 | } 663 | 664 | for(uint8_t i = 0; i < relayCount; i++) { 665 | objGenie.WriteObject(GENIE_OBJ_LED, i, (objRELAY.get(i) == AQUA_RELAY_ON ? 1 : 0)); 666 | } 667 | 668 | delay(100); 669 | } 670 | 671 | /*** print status to serial ***/ 672 | void printStatusToSerial(AQUA_datetime *datetimeStruct, float temp, float pH, int orp) { 673 | Serial.println("");Serial.print("Date: "); 674 | Serial.print(datetimeStruct->day);Serial.print("."); 675 | Serial.print(datetimeStruct->mon);Serial.print("."); 676 | Serial.print(datetimeStruct->year);Serial.print(" (");Serial.print(datetimeStruct->wday);Serial.println(")"); 677 | Serial.print("Time: "); 678 | Serial.print(datetimeStruct->hour);Serial.print(":"); 679 | Serial.print(datetimeStruct->min);Serial.print(":"); 680 | Serial.println(datetimeStruct->sec); 681 | 682 | Serial.print("Temperature: "); Serial.println(temp); 683 | Serial.print("pH: "); Serial.println(pH); 684 | Serial.print("ORP: "); Serial.println(orp); 685 | 686 | for(uint8_t i = 0; i < relayCount; i++) { 687 | Serial.print("Relay");Serial.print(i+1);Serial.print(": ");Serial.println(objRELAY.get(i) == AQUA_RELAY_ON ? "ON" : "OFF"); 688 | } 689 | 690 | delay(100); 691 | } 692 | 693 | /*** setup function ***/ 694 | void setup() { 695 | analogReference(EXTERNAL); //use AREF for reference voltage (connect 3.3V pin to AREF pin) 696 | 697 | if(AQUA_DEBUG_MODE_ON == 1) { 698 | Serial.begin(115200); 699 | Serial.println("Initialization..."); 700 | } 701 | 702 | if(AQUA_DEBUG_MODE_ON == 1) { 703 | Serial.println("Time object initialization..."); 704 | } 705 | objTIME.init(AQUA_TIME_DATA_PIN, AQUA_TIME_CLOCK_PIN, DS_TYPE_3231, true, 1); //dataPin(SDA), clockPin(SCLK), DS3231, use DST, time zone (+1 = SEC) 706 | 707 | if(AQUA_DEBUG_MODE_ON == 1) { 708 | Serial.println("Relay object initialization..."); 709 | } 710 | objRELAY.init(AQUA_RELAY_FIRST_PIN, AQUA_RELAY_ALARMS, AQUA_RELAY_TIMERS, AQUA_RELAY_TIMER_PARTS, AQUA_RELAY_ALARMS_ADDR, AQUA_RELAY_TIMERS_ADDR); //first pin number, number of alarms, number of timers, number of timer parts, alarms address, timers address 711 | 712 | if(AQUA_DEBUG_MODE_ON == 1) { 713 | Serial.println("Temperature object initialization..."); 714 | } 715 | objTEMP.init(AQUA_TEMP_DQ_PIN, AQUA_TEMP_CALIBRATE_POINTS, AQUA_TEMP_CALIBRATE_ADDR); //pin(DQ) - a 4.7K resistor is necessary, number of calibrating points, calibrate address 716 | 717 | if(AQUA_DEBUG_MODE_ON == 1) { 718 | Serial.println("pH object initialization..."); 719 | } 720 | objPH.init(AQUA_PH_VOUT_PIN, AQUA_PH_VOCM_PIN, AQUA_PH_CALIBRATE_POINTS, AQUA_PH_CALIBRATE_ADDR, AQUA_ANALOG_VREF, AQUA_ADC_BIT_RESOLUTION); //VOUT pin, VOCM pin, number of calibrating points, calibrate address, vRef, ADC bit resolution 721 | // objPH.useADC141S626(AQUA_SPI_PH_VOUT_PIN, AQUA_SPI_MISO_PIN, AQUA_SPI_MOSI_PIN, AQUA_SPI_SCLK_PIN, AQUA_SPI_SS_PIN); 722 | // objPH.useADS1115(AQUA_ADS1115_SDA_PIN, AQUA_ADS1115_SCL_PIN); 723 | 724 | if(AQUA_DEBUG_MODE_ON == 1) { 725 | Serial.println("ORP object initialization..."); 726 | } 727 | objORP.init(AQUA_ORP_VOUT_PIN, AQUA_ORP_VOCM_PIN, AQUA_ORP_CALIBRATE_POINTS, AQUA_ORP_CALIBRATE_ADDR, AQUA_ANALOG_VREF, AQUA_ADC_BIT_RESOLUTION); //VOUT pin, VOCM pin, number of calibrating points, calibrate address, vRef, ADC bit resolution 728 | // objORP.useADC141S626(AQUA_SPI_ORP_VOUT_PIN, AQUA_SPI_MISO_PIN, AQUA_SPI_MOSI_PIN, AQUA_SPI_SCLK_PIN, AQUA_SPI_SS_PIN); 729 | // objORP.useADS1115(AQUA_ADS1115_SDA_PIN, AQUA_ADS1115_SCL_PIN); 730 | 731 | if(AQUA_DEBUG_MODE_ON == 1) { 732 | Serial.print("Setup LCD:");Serial.print(AQUA_LCD_SERIAL);Serial.print(":");Serial.println(AQUA_LCD_SERIAL_SPEED); 733 | } 734 | switch(AQUA_LCD_SERIAL) { 735 | case 3: 736 | Serial3.begin(AQUA_LCD_SERIAL_SPEED); 737 | objGenie.Begin(Serial3); 738 | break; 739 | case 2: 740 | Serial2.begin(AQUA_LCD_SERIAL_SPEED); 741 | objGenie.Begin(Serial2); 742 | break; 743 | case 1: 744 | default: 745 | Serial1.begin(AQUA_LCD_SERIAL_SPEED); 746 | objGenie.Begin(Serial1); 747 | break; 748 | } 749 | objGenie.AttachEventHandler(lcdEventHandler); 750 | pinMode(AQUA_LCD_RESET_PIN, OUTPUT); //Set D4 on Arduino to Output 751 | digitalWrite(AQUA_LCD_RESET_PIN, LOW); //Reset the Display via D4 752 | delay(100); 753 | digitalWrite(AQUA_LCD_RESET_PIN, HIGH); //unReset the Display via D4 754 | delay(4000); //let the display start up 755 | displayForm(GENIE_FORM_MAIN); 756 | objGenie.WriteContrast(1); 757 | objLCD.init(AQUA_LCD_TIMEOUT_ADDR); 758 | 759 | if(AQUA_DEBUG_MODE_ON == 1) { 760 | Serial.println("Setup Watchdog Timer..."); 761 | } 762 | setupWDT(); 763 | pinMode(AQUA_WAKEUP_BUTTON, INPUT); 764 | digitalWrite(AQUA_WAKEUP_BUTTON, HIGH); 765 | pinMode(AQUA_ACTIVITY_LED, OUTPUT); 766 | digitalWrite(AQUA_ACTIVITY_LED, HIGH); 767 | 768 | wakeup = 1; 769 | wakeupLCD = 1; 770 | if(AQUA_DEBUG_MODE_ON == 1) { 771 | Serial.println("Ready for use!"); 772 | } 773 | delay(100); 774 | } 775 | 776 | /*** loop function ***/ 777 | void loop() { 778 | objGenie.DoEvents(); 779 | if(wakeupLCD == 1 && calibration > GENIE_CALIBRATION_OFF) { 780 | if(calWV < millis() - 500) { 781 | writeActualValue(); 782 | calWV = millis(); 783 | } 784 | } 785 | if(wakeupButton == 1) { 786 | wakeupButton = 0; 787 | wakeup = 1; 788 | inactivity = millis(); 789 | if(AQUA_DEBUG_MODE_ON == 1) { 790 | Serial.println("");Serial.println("pin2Interrupt..."); 791 | } 792 | if(wakeupLCD == 0) { 793 | displayForm(GENIE_FORM_MAIN); 794 | objGenie.WriteContrast(1); 795 | wakeupLCD = 1; 796 | } 797 | } 798 | if(wakeup == 1) { 799 | wakeup = 0; 800 | checkAll(); 801 | if(wakeupLCD == 0) { 802 | enterSleep(); 803 | } 804 | } 805 | } 806 | -------------------------------------------------------------------------------- /Eagle/Aqua_ph_orp/Aqua_ph_orp.txt: -------------------------------------------------------------------------------- 1 | R1,R11 - RESISTOR, 0603, 27R4, 1% - VISHAY DRALORIC, CRCW060327R4FKEA 2 | C4,C14 - CAPACITOR CERAMIC, 0.1UF, 16V, X7R, 0603 - AVX, 0603YC104JAT2A 3 | C3,C13 - CAPACITOR TANTALUM, 10UF, 10V, 10%, 1206 - AVX, TAJA106K010RNJ 4 | C6,C16 - CAPACITOR TANTALUM, 10UF, 10V, 10%, 1206 - AVX, TAJA106K010RNJ 5 | C7,C17 - CAPACITOR CERAMIC, 0.1UF, 100V, X7R, 1206 - AVX, 12061C104KAT2A -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Rastislav Birka 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Pics/VisiGenie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/Pics/VisiGenie.png -------------------------------------------------------------------------------- /Pics/lcd1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/Pics/lcd1.jpg -------------------------------------------------------------------------------- /Pics/lcd2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/Pics/lcd2.jpg -------------------------------------------------------------------------------- /Pics/lcd3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/Pics/lcd3.jpg -------------------------------------------------------------------------------- /Pics/lcd4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/Pics/lcd4.jpg -------------------------------------------------------------------------------- /Pics/lcd5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/Pics/lcd5.jpg -------------------------------------------------------------------------------- /Pics/lcd6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/Pics/lcd6.jpg -------------------------------------------------------------------------------- /Pics/pH_orp_module.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/Pics/pH_orp_module.jpg -------------------------------------------------------------------------------- /Pics/power1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/Pics/power1.jpg -------------------------------------------------------------------------------- /Pics/power2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/Pics/power2.jpg -------------------------------------------------------------------------------- /Pics/power3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rastocs2/AquariumController/d6b1d49d843039aeb877a38d2627ae51c7258b6c/Pics/power3.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AquariumController 2 | ================== 3 | 4 | Aquarium controller based on Arduino and 4D Systems Intelligent Display Module. 5 | 6 | ## Components 7 | 8 | 1. Arduino Mega 2560 R3 (http://arduino.cc/en/Main/ArduinoBoardMega2560) 9 | 2. 4D Systems µLCD-28PTU (http://www.4dsystems.com.au/product/1/8/4D_Intelligent_Display_Modules/uLCD_28PTU/) 10 | 3. Real Time Clock Module DS3231 - it is much more accurate than DS1307 (http://www.ebay.com/sch/i.html?_trksid=p2050601.m570.l1313.TR0.TRC0.XDS3231+AT24C32&_nkw=DS3231+AT24C32&_sacat=0&_from=R40) 11 | 4. 8 Channel 5V Opto-Isolated Relay Module Shield (http://www.ebay.com/sch/i.html?_odkw=8+Channel+5V+Relay+Module&_osacat=0&_from=R40&_trksid=p2045573.m570.l1311.R1.TR3.TRC2.A0&_nkw=8+channel+5v+relay+module&_sacat=0) 12 | 5. Digital Temperature Sensor DS18B20 (http://www.ebay.com/sch/i.html?_odkw=DS18B20+Waterproof&_osacat=0&_from=R40&_trksid=p2045573.m570.l1311.R1.TR2.TRC1.A0.XDS18B20+aterproof&_nkw=ds18b20+waterproof&_sacat=0) 13 | 6. pH module based on LMP91200 (http://www.ti.com/product/lmp91200) 14 | 7. ORP module based on LMP91200 (http://www.ti.com/product/lmp91200) 15 | 8. WiFi module based on CC3000 (http://www.ti.com/product/cc3000) - will finished in version 3.0 16 | -------------------------------------------------------------------------------- /Versions.txt: -------------------------------------------------------------------------------- 1 | 07.05.2014 - version 2.1 2 | * preparation for using ADC141S626 and ADS1115 in PH and ORP module 3 | 12.01.2014 - version 2.0 4 | * added pH and ORP module 5 | 02.01.2014 - version 1.2 6 | * automatic Daylight Time Saving 7 | 30.12.2013 - version 1.1 8 | * support for DS3231 9 | 24.11.2013 - version 1.0 10 | * Initial version without pH module and ORP module 11 | --------------------------------------------------------------------------------