├── .clang-format ├── .github └── workflows │ ├── build.yml │ └── publish_doxygen.yml ├── .gitignore ├── 4mb_inc_ota.csv ├── Doxyfile ├── LICENSE ├── README.md ├── bin └── wifi-reset.bin ├── data ├── 5x8_lcd.eot ├── 5x8_lcd.woff ├── README.txt ├── fermenttemp_logo.svg ├── index.css.gz ├── index.html └── index.js.gz ├── docs ├── Makefile ├── make.bat ├── requirements.txt └── source │ ├── BrewPi Algorithm.md │ ├── Controller Configuration Options.md │ ├── Installing the Firmware.md │ ├── Selecting an ESP Board.md │ ├── Solder Free BrewPi.md │ ├── Supported Sensors & Actuators.md │ ├── Web Interface.md │ ├── conf.py │ └── index.md ├── lib └── readme.txt ├── platformio.ini ├── scripts ├── gen_version.py └── get_port.py └── src ├── Actuator.cpp ├── Actuator.h ├── ActuatorArduinoPin.cpp ├── ActuatorArduinoPin.h ├── ActuatorAutoOff.h ├── ActuatorTPLink.cpp ├── ActuatorTPLink.h ├── Brewpi.h ├── BrewpiStrings.cpp ├── BrewpiStrings.h ├── Buzzer.cpp ├── Buzzer.h ├── CommandProcessor.cpp ├── CommandProcessor.h ├── Config.h ├── ConfigDefault.h ├── DS2413.cpp ├── DS2413.h ├── DallasTempNG.cpp ├── DallasTempNG.h ├── DeviceManager.cpp ├── DeviceManager.h ├── DeviceManagerFiles.cpp ├── DeviceNameManager.cpp ├── DeviceNameManager.h ├── Display.cpp ├── Display.h ├── DisplayBase.h ├── DisplayLcd.cpp ├── DisplayLcd.h ├── DisplayTFT.cpp ├── DisplayTFT.h ├── ESPEepromAccess.h ├── ESP_BP_WiFi.cpp ├── ESP_BP_WiFi.h ├── EepromManager.cpp ├── EepromManager.h ├── EepromStructs.cpp ├── EepromStructs.h ├── Emulator.h ├── FastDigitalPin.h ├── FilterCascaded.cpp ├── FilterCascaded.h ├── FilterFixed.cpp ├── FilterFixed.h ├── IicLcd.cpp ├── IicLcd.h ├── InkbirdTempSensor.cpp ├── InkbirdTempSensor.h ├── JsonKeys.h ├── JsonMessages.cpp ├── JsonMessages.h ├── LogMessages.h ├── Logger.cpp ├── Logger.h ├── Menu.cpp ├── Menu.h ├── NullLcdDriver.cpp ├── NullLcdDriver.h ├── NumberFormats.cpp ├── NumberFormats.h ├── OLEDFourBit.cpp ├── OLEDFourBit.h ├── OneWireActuator.h ├── OneWireDevices.h ├── OneWireTempSensor.cpp ├── OneWireTempSensor.h ├── PiLink.h ├── PiStream.h ├── Pins.h ├── PromServer.cpp ├── PromServer.h ├── Random.cpp ├── RotaryEncoder.cpp ├── RotaryEncoder.h ├── Sensor.cpp ├── Sensor.h ├── SensorArduinoPin.h ├── SettingLoader.cpp ├── SettingLoader.h ├── SettingsManager.cpp ├── SettingsManager.h ├── Simulator.cpp ├── Simulator.h ├── SpiLcd.cpp ├── SpiLcd.h ├── TempControl.cpp ├── TempControl.h ├── TempSensor.cpp ├── TempSensor.h ├── TempSensorBasic.h ├── TempSensorDisconnected.h ├── TempSensorExternal.h ├── TempSensorMock.h ├── TemperatureFormats.cpp ├── TemperatureFormats.h ├── Ticks.cpp ├── Ticks.h ├── TicksArduino.h ├── TiltTempSensor.cpp ├── TiltTempSensor.h ├── brewpi-esp8266.cpp ├── http_server.cpp ├── http_server.h ├── http_server_generic.cpp ├── resetreasons.h ├── tplink ├── TPLinkConnector.cpp ├── TPLinkConnector.h ├── TPLinkDevice.cpp ├── TPLinkDevice.h ├── TPLinkPlug.cpp ├── TPLinkPlug.h ├── TPLinkScanner.cpp └── TPLinkScanner.h ├── uptime.cpp ├── uptime.h └── wireless ├── BTScanner.cpp ├── BTScanner.h ├── Inkbird.cpp ├── Inkbird.h ├── Tilt.cpp └── Tilt.h /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveMacros: false 7 | AlignConsecutiveAssignments: false 8 | AlignConsecutiveDeclarations: false 9 | AlignEscapedNewlines: Right 10 | AlignOperands: true 11 | AlignTrailingComments: true 12 | AllowAllArgumentsOnNextLine: true 13 | AllowAllConstructorInitializersOnNextLine: true 14 | AllowAllParametersOfDeclarationOnNextLine: true 15 | AllowShortBlocksOnASingleLine: Never 16 | AllowShortCaseLabelsOnASingleLine: false 17 | AllowShortFunctionsOnASingleLine: All 18 | AllowShortLambdasOnASingleLine: All 19 | AllowShortIfStatementsOnASingleLine: Never 20 | AllowShortLoopsOnASingleLine: false 21 | AlwaysBreakAfterDefinitionReturnType: None 22 | AlwaysBreakAfterReturnType: None 23 | AlwaysBreakBeforeMultilineStrings: false 24 | AlwaysBreakTemplateDeclarations: MultiLine 25 | BinPackArguments: true 26 | BinPackParameters: true 27 | BraceWrapping: 28 | AfterCaseLabel: false 29 | AfterClass: false 30 | AfterControlStatement: false 31 | AfterEnum: false 32 | AfterFunction: false 33 | AfterNamespace: false 34 | AfterObjCDeclaration: false 35 | AfterStruct: false 36 | AfterUnion: false 37 | AfterExternBlock: false 38 | BeforeCatch: false 39 | BeforeElse: false 40 | IndentBraces: false 41 | SplitEmptyFunction: true 42 | SplitEmptyRecord: true 43 | SplitEmptyNamespace: true 44 | BreakBeforeBinaryOperators: None 45 | BreakBeforeBraces: Attach 46 | BreakBeforeInheritanceComma: false 47 | BreakInheritanceList: BeforeColon 48 | BreakBeforeTernaryOperators: true 49 | BreakConstructorInitializersBeforeComma: false 50 | BreakConstructorInitializers: BeforeColon 51 | BreakAfterJavaFieldAnnotations: false 52 | BreakStringLiterals: true 53 | ColumnLimit: 120 54 | CommentPragmas: '^ IWYU pragma:' 55 | CompactNamespaces: false 56 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 57 | ConstructorInitializerIndentWidth: 4 58 | ContinuationIndentWidth: 4 59 | Cpp11BracedListStyle: true 60 | DeriveLineEnding: true 61 | DerivePointerAlignment: false 62 | DisableFormat: false 63 | ExperimentalAutoDetectBinPacking: false 64 | FixNamespaceComments: true 65 | ForEachMacros: 66 | - foreach 67 | - Q_FOREACH 68 | - BOOST_FOREACH 69 | IncludeBlocks: Preserve 70 | IncludeCategories: 71 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 72 | Priority: 2 73 | SortPriority: 0 74 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 75 | Priority: 3 76 | SortPriority: 0 77 | - Regex: '.*' 78 | Priority: 1 79 | SortPriority: 0 80 | IncludeIsMainRegex: '(Test)?$' 81 | IncludeIsMainSourceRegex: '' 82 | IndentCaseLabels: false 83 | IndentGotoLabels: true 84 | IndentPPDirectives: None 85 | IndentWidth: 2 86 | IndentWrappedFunctionNames: false 87 | JavaScriptQuotes: Leave 88 | JavaScriptWrapImports: true 89 | KeepEmptyLinesAtTheStartOfBlocks: true 90 | MacroBlockBegin: '' 91 | MacroBlockEnd: '' 92 | MaxEmptyLinesToKeep: 1 93 | NamespaceIndentation: None 94 | ObjCBinPackProtocolList: Auto 95 | ObjCBlockIndentWidth: 2 96 | ObjCSpaceAfterProperty: false 97 | ObjCSpaceBeforeProtocolList: true 98 | PenaltyBreakAssignment: 2 99 | PenaltyBreakBeforeFirstCallParameter: 19 100 | PenaltyBreakComment: 300 101 | PenaltyBreakFirstLessLess: 120 102 | PenaltyBreakString: 1000 103 | PenaltyBreakTemplateDeclaration: 10 104 | PenaltyExcessCharacter: 1000000 105 | PenaltyReturnTypeOnItsOwnLine: 60 106 | PointerAlignment: Right 107 | ReflowComments: true 108 | SortIncludes: true 109 | SortUsingDeclarations: true 110 | SpaceAfterCStyleCast: false 111 | SpaceAfterLogicalNot: false 112 | SpaceAfterTemplateKeyword: true 113 | SpaceBeforeAssignmentOperators: true 114 | SpaceBeforeCpp11BracedList: false 115 | SpaceBeforeCtorInitializerColon: true 116 | SpaceBeforeInheritanceColon: true 117 | SpaceBeforeParens: ControlStatements 118 | SpaceBeforeRangeBasedForLoopColon: true 119 | SpaceInEmptyBlock: false 120 | SpaceInEmptyParentheses: false 121 | SpacesBeforeTrailingComments: 1 122 | SpacesInAngles: false 123 | SpacesInConditionalStatement: false 124 | SpacesInContainerLiterals: true 125 | SpacesInCStyleCastParentheses: false 126 | SpacesInParentheses: false 127 | SpacesInSquareBrackets: false 128 | SpaceBeforeSquareBrackets: false 129 | Standard: Latest 130 | StatementMacros: 131 | - Q_UNUSED 132 | - QT_REQUIRE_VERSION 133 | TabWidth: 8 134 | UseCRLF: false 135 | UseTab: Never 136 | ... 137 | 138 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - experimental 7 | - master 8 | # tags: 9 | # - "v*" 10 | # pull_request: 11 | # types: [ open, synchronize, edited, reopened, closed ] 12 | 13 | jobs: 14 | build: 15 | name: Build bins for ${{ matrix.pio_env }} 16 | strategy: 17 | # Ensure that a builder finishes even if another fails 18 | fail-fast: false 19 | matrix: 20 | pio_env: ['esp32_wifi_tft', 'esp32_wifi_iic', 'esp8266_wifi', 'esp8266_serial', 'esp32_s2_wifi', 'esp32_s2_serial'] 21 | 22 | runs-on: ubuntu-latest 23 | 24 | steps: 25 | - uses: actions/checkout@v3.3.0 26 | - run: git fetch --prune --unshallow 27 | 28 | - name: Cache pip 29 | uses: actions/cache@v3.2.2 30 | with: 31 | path: ~/.cache/pip 32 | key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} 33 | restore-keys: | 34 | ${{ runner.os }}-pip- 35 | 36 | - name: Cache PlatformIO 37 | uses: actions/cache@v3.2.2 38 | with: 39 | path: ~/.platformio 40 | key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} 41 | 42 | - name: Set up Python 43 | uses: actions/setup-python@v4.4.0 44 | 45 | - name: Install PlatformIO 46 | run: | 47 | python -m pip install --upgrade pip 48 | pip install --upgrade platformio 49 | 50 | - name: Build firmware 51 | run: | 52 | pio run -e ${{ matrix.pio_env }} 53 | # pio run -e ${{ matrix.pio_env }} --target buildfs 54 | # sh ./copy_bins.sh 55 | 56 | - name: Copy firmware 57 | continue-on-error: true 58 | run: | 59 | cp .pio/build/${{ matrix.pio_env }}/firmware.bin bin/${{ matrix.pio_env }}_firmware.bin 60 | 61 | - name: Copy partitions 62 | continue-on-error: true 63 | run: | 64 | cp .pio/build/${{ matrix.pio_env }}/partitions.bin bin/${{ matrix.pio_env }}_partitions.bin 65 | 66 | - name: Build filesystem 67 | run: | 68 | pio run -e ${{ matrix.pio_env }} --target buildfs 69 | # sh ./copy_bins.sh 70 | 71 | - name: Copy Spiffs 72 | continue-on-error: true 73 | run: | 74 | cp .pio/build/${{ matrix.pio_env }}/spiffs.bin bin/${{ matrix.pio_env }}_spiffs.bin 75 | 76 | - name: Copy LittleFS 77 | continue-on-error: true 78 | run: | 79 | cp .pio/build/${{ matrix.pio_env }}/littlefs.bin bin/${{ matrix.pio_env }}_littlefs.bin 80 | 81 | # - name: "Create Prerelease" 82 | # uses: "marvinpinto/action-automatic-releases@latest" 83 | # with: 84 | # repo_token: "${{ secrets.GITHUB_TOKEN }}" 85 | # prerelease: true 86 | # files: | 87 | # LICENSE 88 | # bin/*.bin 89 | 90 | - name: Create Draft Release 91 | uses: softprops/action-gh-release@v1 92 | # if: startsWith(github.ref, 'refs/tags/') 93 | with: 94 | body: "Draft release" 95 | # note you'll typically need to create a personal access token 96 | # with permissions to create releases in the other repo 97 | token: ${{ secrets.GITHUB_TOKEN }} 98 | draft: true 99 | prerelease: true 100 | files: | 101 | LICENSE 102 | bin/*.bin 103 | env: 104 | GITHUB_REPOSITORY: thorrak/brewpi-esp8266 -------------------------------------------------------------------------------- /.github/workflows/publish_doxygen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Publish Doxygen Docs" 3 | 4 | on: 5 | push: 6 | branches: 7 | - "master" 8 | - "esp32" 9 | 10 | jobs: 11 | publish: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | 17 | - name: Build Doxygen 18 | uses: mattnotmitt/doxygen-action@v1.1.0 19 | with: 20 | doxyfile-path: 'Doxyfile' 21 | 22 | - name: Publish Doxygen to GitHub Pages 23 | uses: peaceiris/actions-gh-pages@v3.6.4 24 | with: 25 | github_token: ${{ secrets.GITHUB_TOKEN }} 26 | publish_dir: ./apidocs/html 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .pioenvs 2 | CMakeListsPrivate.txt 3 | .piolibdeps 4 | .idea/ 5 | cmake-build*/ 6 | 7 | 8 | CMakeCache.txt 9 | CMakeFiles 10 | CMakeScripts 11 | Testing 12 | cmake_install.cmake 13 | install_manifest.txt 14 | compile_commands.json 15 | CTestTestfile.cmake 16 | 17 | 18 | /.vscode 19 | /.pio 20 | 21 | .DS_Store 22 | 23 | bin/esp8266_wifi.bin 24 | bin/esp8266_serial.bin 25 | bin/esp32_wifi_tft.bin 26 | 27 | apidocs/ 28 | *.sw? 29 | 30 | src/Version.h 31 | 32 | # Virtualenv / Sphinx 33 | /venv 34 | /docs/venv 35 | /docs/_build 36 | -------------------------------------------------------------------------------- /4mb_inc_ota.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | nvs, data, nvs, 0x9000, 0x5000, 3 | otadata, data, ota, 0xe000, 0x2000, 4 | app0, app, ota_0, 0x10000, 0x190000, 5 | app1, app, ota_1, 0x1A0000,0x190000, 6 | spiffs, data, spiffs, 0x330000,0xD0000, -------------------------------------------------------------------------------- /bin/wifi-reset.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorrak/brewpi-esp8266/b6e45cd6ec49fd1e45c629d9871d0cae3060cea4/bin/wifi-reset.bin -------------------------------------------------------------------------------- /data/5x8_lcd.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorrak/brewpi-esp8266/b6e45cd6ec49fd1e45c629d9871d0cae3060cea4/data/5x8_lcd.eot -------------------------------------------------------------------------------- /data/5x8_lcd.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorrak/brewpi-esp8266/b6e45cd6ec49fd1e45c629d9871d0cae3060cea4/data/5x8_lcd.woff -------------------------------------------------------------------------------- /data/README.txt: -------------------------------------------------------------------------------- 1 | Files in this directory are written to the SPIFFS partition 2 | (including this one, which is intentional) -------------------------------------------------------------------------------- /data/index.css.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorrak/brewpi-esp8266/b6e45cd6ec49fd1e45c629d9871d0cae3060cea4/data/index.css.gz -------------------------------------------------------------------------------- /data/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Temperature Control Interface 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /data/index.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorrak/brewpi-esp8266/b6e45cd6ec49fd1e45c629d9871d0cae3060cea4/data/index.js.gz -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=_build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | myst-parser==0.19.1 2 | sphinx==6.1.3 3 | sphinx_rtd_theme==1.2.0 4 | -------------------------------------------------------------------------------- /docs/source/BrewPi Algorithm.md: -------------------------------------------------------------------------------- 1 | # BrewPi Algorithm 2 | 3 | BrewPi uses a (PID algorithm)[https://en.wikipedia.org/wiki/PID_controller] to control the fermentation temperature of beer very precisely. The algorithm works by adjusting the temperature setting of the fridge a fermenter is in based on the desired temperature of the beer. This is done by an automated process, similar to stationing a robot next to your fridge's thermostat and telling it to adjust the thermostat up or down based on where you think it needs to be in order to get the beer temperature correct. 4 | 5 | Just as when typically adjusting the thermostat on a refrigerator, whether or not the fridge turns on takes into account factors such as how far the current temperature is from the setpoint and how long it has been since the last cooling cycle took place (compressor protection). Heating or cooling will take place until the fridge temperature meets or surpasses the setpoint (though similar to the built in thermostat, there may be a "minimum run time" so as to protect the compressor). When using a heater the algorithm continues to simply change the fridge temperature setpoint - toggling cooling or heating depending on whether the fridge temperature is above or below the desired fridge setpoint. 6 | 7 | The BrewPi algorithm determines the optimal fridge setpoint based on the beer temperature and how historically changing the fridge thermostat has affected the beer temperature. The PID algorithm measures error in the 8 | 9 | However, the algorithm has limits, as it uses a single algorithm to control both heating and cooling. This assumption assumes that both heating and cooling will be impacted by the same degree of error which means that you will generally want to match your heating and cooling power, as well as the degree to which the heating/cooling can be picked up by the fridge sensor. 10 | 11 | -------------------------------------------------------------------------------- /docs/source/Controller Configuration Options.md: -------------------------------------------------------------------------------- 1 | # Controller Configuration Options 2 | 3 | 4 | ## User Guide to Configuration 5 | 6 | The majority of the configuration of your BrewPi happens behind-the-scenes, either handled automatically by the controller itself or managed by Fermentrack or BrewPi Remix. 7 | 8 | 9 | ### "Low Delay" Mode 10 | 11 | BrewPi implements a number of protections designed to prevent damage to compressor-based cooling systems such as refrigerators, kegerators, or keezers. These include requiring cooling to run for a minimum period of time before being turned off, requiring a minimum amount of time to pass with the cooling off before allowing it to come back on, and requiring a minimum amount of time to pass before switching between heat & cooling. Low Delay mode reduces the delays associated with cooling 12 | 13 | | | **Normal** | **"Low Delay"** | 14 | |------------------------------------------------|------------|-----------------| 15 | | Minimum Cooling "Off" Time | 300s | 60s | 16 | | Minimum Heat "Off" Time | 300s | 300s | 17 | | Minimum Cooling "On" Time | 180s | 20s | 18 | | Minimum Heat "On" Time | 180s | 180s | 19 | | Min Cool "Off" Time (Fridge Constant Mode) | 600s | 60s | 20 | | Min time between switching between heat & cool | 600s | 600s | 21 | 22 | 23 | :::{Warning} 24 | Low Delay mode should never be used with compressor-based cooling as it may damage your equipment. Low Delay mode is intended for other types of cooling, such as glycol, chilled water pumps, fans/ice, or peltier coolers. 25 | ::: 26 | 27 | 28 | ### Rotate TFT 29 | 30 | TFT-based builds (ESP32) can have the display rotated if it is inserted in the case upside down (or the manufacturer has changed the default orientation). If your screen is upside-down, toggle this on. 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /docs/source/Installing the Firmware.md: -------------------------------------------------------------------------------- 1 | # Installing the Firmware 2 | 3 | ## BrewFlasher & Fermentrack 4 | 5 | The easiest way to install the firmware is using either [BrewFlasher](http://www.brewflasher.com/), [BrewFlasher Web Edition](https://web.brewflasher.com/) or the firmware flow in [Fermentrack](http://www.fermentrack.com/). 6 | 7 | BrewFlasher is a standalone application for MacOS and Windows that allows for the firmware to be automatically downloaded & flashed to your controller. It was specifically designed to make flashing *this* project easy. For most users, this is the ideal installation method. 8 | 9 | BrewFlasher Web Edition is a browser-based version of BrewFlasher that allows you to install firmware using a compatible web browser without needing to download or install the desktop version of BrewFlasher. It supports the same list of firmware as BrewFlasher, but requires that you 10 | 11 | Fermentrack is a web interface that BrewPi controllers can connect to/be managed by. If you were already planning on using Fermentrack to manage your BrewPi controller then this is a perfect alternative to either using BrewFlasher or flashing manually. 12 | 13 | 14 | ## esptool 15 | 16 | The firmware can also be installed using esptool (which is what BrewFlasher uses behind-the-scenes). This is not recommended for most users, as you will need to craft the correct command to flash the correct files to the proper offsets, which will change depending on the specific firmware you are looking to flash. 17 | 18 | 19 | 20 | ## NodeMCU Flasher for Windows (ESP8266-only) 21 | 22 | ESP8266 modules can also be flashed using [NodeMCU-PyFlasher](https://github.com/marcelstoer/nodemcu-pyflasher). 23 | 24 | # Configuring WiFi 25 | Once you've flashed firmware to your ESP device, you'll need to configure it to connect to your WiFi network. For that purpose, the firmware creates a WiFi access point named `BrewPiAP`, with a password of `brewpiesp`. Connect to that access point and, if your device doesn't pull up a configuration page on its own, browse to `http://192.168.4.1`. Then click on **Configure WiFi,** and configure it to connect to your WiFi network. 26 | -------------------------------------------------------------------------------- /docs/source/Selecting an ESP Board.md: -------------------------------------------------------------------------------- 1 | # Selecting a Board 2 | 3 | The BrewPi-ESP project supports a number of different microcontrollers with differing features. Supported controllers include: 4 | 5 | | **Microcontroller** | **DS18b20 Temp Sensors** | **Connected Relays** | **WiFi Support** | **LCD2004 (IIC) Support** | **TFT Screen Support** | **Kasa WiFi Relay** | **Tilt/Inkbird Bluetooth Temp Sensors** | 6 | |---------------------|--------------------------|----------------------|--------------------|---------------------------|------------------------|---------------------|-----------------------------------------| 7 | | Arduino* | :heavy_check_mark: | :heavy_check_mark: | | :heavy_check_mark:* | | | | 8 | | ESP8266 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | | | 9 | | ESP32 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | 10 | | ESP32-S2 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | :heavy_check_mark: | | 11 | 12 | **Note** - "Classic" BrewPi builds are based on Arduinos, which are shown in the table above for comparison. There is an (optional) IIC-compatible build of the Arduino firmware available, but "classic" builds did not support this feature. 13 | 14 | For new builds, I recommend the ESP32 as it supports the widest range of features. The specific ESP32 board I recommend is the [LoLin D32 Pro](https://www.aliexpress.us/item/2251832696801305.html) alongside their [TFT Screen](https://www.aliexpress.us/item/2251832733414978.html) and [TFT Cable](https://www.aliexpress.us/item/2251832662518722.html). 15 | 16 | For smaller builds or builds using existing PCBs designed for the ESP8266 I recommend the [LoLin S2 Mini](https://www.aliexpress.us/item/3256802958877264.html). This is a pin-compatible replacement for the LoLin D1 Mini and can be dropped into most existing builds. 17 | 18 | I maintain a separate repo that contains all of my hardware designs on [GitHub](https://github.com/thorrak/thorrak_hardware/blob/master/BrewPi-ESP8266.md) with full BoMs and build instructions, as well as 3D-printable case designs. For a full how-to on building, take a look there. 19 | -------------------------------------------------------------------------------- /docs/source/Solder Free BrewPi.md: -------------------------------------------------------------------------------- 1 | # Building a "Solder Free" Brewpi 2 | 3 | Through the combination of the ESP32 firmware, Bluetooth support, and Kasa WiFi Switch support, it is now possible to build a BrewPi temperature controller without the need to solder anything. Here's how to do it: 4 | 5 | 6 | 7 | ## Bill of Materials 8 | 9 | ### Controller 10 | 11 | * 1 x [LoLin D32 Pro](https://www.aliexpress.us/item/2251832696801305.html) 12 | * 1 x [LoLin TFT Screen](https://www.aliexpress.us/item/2251832733414978.html) 13 | * 1 x [LoLin TFT Cable](https://www.aliexpress.us/item/2251832662518722.html) 14 | * 1 x [Case (including screws)](https://github.com/thorrak/thorrak_hardware/tree/master/TiltBridge%20Containers/D32%20Pro%20Container) 15 | 16 | Although any ESP32 board can be used, and the screen/case are not mandatory, I find that the above hardware in combination with a 3D printed case works perfectly. 17 | 18 | 19 | ### Other Components 20 | 21 | * 1-2 x [Kasa Smart Plug](https://www.kasasmart.com/us/products/smart-plugs/kasa-smart-plug-mini-ep10) (Heat/Cool Switches) 22 | * 1 x [Inkbird IBS-TH2](https://www.amazon.com/Inkbird-Thermometer-Wireless-Bluetooth-Temperature/dp/B08S3CGZ3Q/) (Fridge Temp Sensor) 23 | * 1 x [Tilt Pro Hydrometer](https://tilthydrometer.com/products/tilt-pro-wireless-hydrometer-and-thermometer) (Beer Temp Sensor) 24 | * 1 x [Inkbird IBS-TH1 Plus](https://www.amazon.com/Inkbird-Bluetooth-Temperature-Thermometer-Hygrometer/dp/B07DQNFJVL/) (Beer Temp Sensor) 25 | 26 | You only need one of the Tilt Pro or Inkbird IBS-TH1 Plus to act as a beer temperature sensor -- The Tilt Pro is inserted directly into your beer and will measure the temperature floating on top, or you can use an Inkbird IBS-TH1 Plus which has a wired temperature sensor that can be snaked into a thermowell. Although regular, non-pro Tilts can be used, I do not recommend them as the thermometer only measures in whole-degree increments. 27 | 28 | The EP10 Mini Kasa Smart Plug linked above supports loads up to 15A sustained, which should be sufficient for most heating/cooling setups -- please be sure not to overload the switch. 29 | 30 | 31 | ## Instructions 32 | 33 | Assembly/setup generally takes 10 minutes or less. To set up your controller, simply follow these steps: 34 | 35 | 1. If using the case, secure the LoLin D32 Pro into the case bottom using the appropriate screws. 36 | 2. Plug the LoLin TFT Screen into the D32 Pro using the LoLin TFT Cable 37 | 3. If using the case, insert the screen/cable into the case, and secure the case lid to the case base using the appropriate screws 38 | 4. Flash the BrewPi-ESP WiFi firmware to your D32 Pro using [these instructions](Installing%20the%20Firmware.md) 39 | 5. Using a phone or other WiFi device, connect to the "BrewPiAP" WiFi network that your controller creates and connect it to your WiFi network 40 | 5. Connect the Kasa Smart Plug to the same WiFi network as your BrewPi by following the instructions included with the switches 41 | 6. Using a phone or other WiFi device connected to the same WiFi network, log into the web interface by typing the IP address displayed in the lower left corner of the BrewPi screen into a web browser 42 | 7. Click "Set Up Sensors/Actuators" and assign the appropriate functions to your Kasa switches, Inkbird temperature sensor, and Tilt hydrometer 43 | 8. Connect your controller to your installation of [Fermentrack](http://www.fermentrack.com/) or [BrewPi Remix](http://www.brewpiremix.com/) 44 | 45 | Enjoy your new BrewPi temperature controller! 46 | -------------------------------------------------------------------------------- /docs/source/Supported Sensors & Actuators.md: -------------------------------------------------------------------------------- 1 | # Supported Temperature Sensors & Switches/Actuators 2 | 3 | 4 | ## Actuators (Switches/Relays) 5 | 6 | Two types of actuators are currently supported: Pin-based and Kasa WiFi Switches: 7 | 8 | ### Pin-based Actuators 9 | 10 | Pin-based actuators are the traditional type used with BrewPi where an output pin on the controller turns on/off based on whether the controller is calling for heating or cooling. This pin is typically then connected to a relay which then switches the load of the heater/cooler. The "sainsmart" style relay boards are slightly unintuitive in that the pin being "high" (on) actually results in the load being turned _off_. To resolve this, there is an "Invert Pin" option that can be set to ensure that these style of boards are properly toggled on/off. 11 | 12 | :::{important} 13 | When setting up a pin, make sure that the device is off when you expect it to be off, and is on when you expect it to be on. Setting the "invert" flag incorrectly can reverse these, resulting in frozen beer (or worse, if your heater runs indefinitely!) 14 | ::: 15 | 16 | ### TPLink Kasa WiFi Smart Switches 17 | 18 | Kasa WiFi Switches are "smart" plugs which allow for your cooling/heating source to be plugged into a WiFi-enabled device that can then be toggled over your network. BrewPi-ESP detects these devices when connected to the same WiFi network, and can control them without using TP Link's cloud. Initial connection of these devices to the internet (along with initial setup) is completed in the Kasa smart phone app -- once complete, these devices should be detected by BrewPi-ESP. 19 | 20 | 21 | ## Temperature Sensors 22 | 23 | There are three types of temperature sensors supported by BrewPi-ESP: OneWire (DS18b20) temperature sensors, Inkbird bluetooth temperature sensors, and Tilt Pro hydrometers. All three types of temperature sensors allow for a calibration offset to be defined: An amount - specified in 1/16 degree C - that will be added to/subtracted from each reading. 24 | 25 | 26 | ### OneWire Sensors (DS18b20) 27 | 28 | OneWire (DS18b20) temperature sensors are the type traditionally used with BrewPi, and are hard-wired to the controller. They can often be purchased in stainless, waterproof housing, connected to several meter long cables, ready for insertion into a thermowell. Most of these sensors are powered via discrete power, but parasite power versions exist -- BrewPi-ESP will not function with parasitic sensors. 29 | 30 | 31 | ### Inkbird Bluetooth Temperature Sensors 32 | 33 | Inkbird manufactures a number of wireless bluetooth temperature sensors, several of which have been tested and work with BrewPi-ESP: 34 | 35 | * Inkbird IBS-TH1 Plus 36 | * Inkbird IBS-TH2 (both temperature only and temperature + humidity) 37 | * Inkbird IBS-TH2 Plus 38 | 39 | The "plus" versions of these sensors typically come with an extendable temperature probe that can be inserted into a thermowell, and oftentimes also include a display. 40 | 41 | 42 | ### Tilt Hydrometers 43 | 44 | Tilt hydrometers are bluetooth devices that measure both the specific gravity and temperature of your fermenting beer. There are two versions available - the Tilt and the Tilt Pro. The Tilt Pro offers temperature resolution of 0.1 F whereas the regular Tilt offers temperature resolution of whole degrees fahrenheit. The Tilt is an ideal solution for setups that lack a thermowell (or instances where the Tilt would be utilized regardless). 45 | 46 | :::{note} 47 | Due to their higher thermal mass and finer resolution, temperature control using a Tilt is only recommended with the Tilt Pro. Use of a non-Pro tilt is possible, but will result in less accurate temperature control. 48 | ::: 49 | 50 | -------------------------------------------------------------------------------- /docs/source/Web Interface.md: -------------------------------------------------------------------------------- 1 | # Using the BrewPi-ESP Web Interface 2 | 3 | 4 | ## Dashboard 5 | 6 | The dashboard contains a "virtual" LCD showing the state of the controller, as well as dashboard panels breaking out the various control points. From this panel you can also change the control mode the controller is using to manage temperatures by clicking the "Change" link on the Control Mode panel. 7 | 8 | 9 | ### Changing Control Mode 10 | 11 | After clicking the "Change" link a window will pop up allowing you to select the new control mode. There are three selectable modes from the web interface, and one mode that may appear if the controller is connected to BrewPi Remix or Fermentrack: 12 | 13 | * **Off** - Temperature control is disabled, and cooling/heating will be turned off 14 | * **Fridge Constant** - The controller will control the fridge/chamber temperature to match a setpoint 15 | * **Beer Constant** - The controller will control the beer temperature, using the fridge temperature as an input to the algorithm 16 | * **Beer Profile** - _Not selectable from the web interface_ - If the controller is connected to BrewPi Remix or Fermentrack and is currently applying a fermentation temperature profile, the controller will be placed in Beer Profile mode. Beer Profile mode is not selectable from the web interface as management of the profile is handled by Fermentrack/BrewPi Remix. 17 | 18 | When selecting Fridge Constant or Beer Constant mode you will be asked to provide a temperature setpoint to control to in the temperature units selected on the controller. 19 | 20 | 21 | ## Set up Sensors/Actuators 22 | 23 | BrewPi-ESP is designed to read temperatures from a number of different types of temperature data sources and use that to control temperature by actuating several types of switches. In order for this to work, BrewPi-ESP must be told which temperature sensors correspond with each data type (beer temp, fridge temp, or room temp) and which actuators correspond to heating/cooling. The Set Up Sensors/Actuators page allows you to see all sensors/actuators known to the controller and assign each device the relevant function. 24 | 25 | More information on supported sensors and actuators can be found in [](Supported Sensors & Actuators.md). 26 | 27 | 28 | ## Controller Settings 29 | 30 | The Controller Settings page allows you to toggle certain settings associated with the controller. A discussion of these settings can be found in [](Controller Configuration Options.md). 31 | 32 | 33 | ## About Controller 34 | 35 | The About Controller page allows you to see the controller's firmware version, the time since last reboot, some debugging information around what caused the last reboot, and the amount of free memory available on the controller. 36 | 37 | 38 | ## Technical Notes 39 | 40 | The BrewPi-ESP front end is written in JavaScript + Vue. The source files for the interface are saved to a [separate repository on GitHub](https://github.com/thorrak/brewpi_esp_ui) and are governed by a different license from BrewPi-ESP. The front end primarily speaks to the controller via a number of JSON api endpoints that were designed specifically for this purpose. Please be aware that these endpoints are not expected to remain static between firmware versions, and _will_ change without notice. 41 | s -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # For the full list of built-in configuration values, see the documentation: 4 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 5 | 6 | # -- Project information ----------------------------------------------------- 7 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 8 | 9 | project = 'BrewPi-ESP' 10 | copyright = '2023, John Beeler' 11 | author = 'John Beeler' 12 | 13 | # -- General configuration --------------------------------------------------- 14 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 15 | 16 | extensions = ['myst_parser'] 17 | 18 | myst_enable_extensions = ["colon_fence"] 19 | 20 | templates_path = ['_templates'] 21 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 22 | 23 | 24 | 25 | # -- Options for HTML output ------------------------------------------------- 26 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 27 | 28 | html_theme = 'sphinx_rtd_theme' 29 | html_static_path = ['_static'] 30 | -------------------------------------------------------------------------------- /docs/source/index.md: -------------------------------------------------------------------------------- 1 | .. BrewPi-ESP documentation master file, created by 2 | sphinx-quickstart on Thu Mar 2 08:43:24 2023. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to BrewPi-ESP's documentation! 7 | ====================================== 8 | 9 | 10 | :::{toctree} 11 | :maxdepth: 1 12 | Installing the Firmware.md 13 | Controller Configuration Options.md 14 | Selecting an ESP Board.md 15 | Solder Free BrewPi.md 16 | Web Interface.md 17 | Supported Sensors & Actuators.md 18 | ::: 19 | 20 | 21 | 22 | 23 | Indices and tables 24 | ================== 25 | 26 | * :ref:`genindex` 27 | * :ref:`modindex` 28 | * :ref:`search` 29 | -------------------------------------------------------------------------------- /lib/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for the project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link to executable file. 4 | 5 | The source code of each library should be placed in separate directory, like 6 | "lib/private_lib/[here are source files]". 7 | 8 | For example, see how can be organized `Foo` and `Bar` libraries: 9 | 10 | |--lib 11 | | |--Bar 12 | | | |--docs 13 | | | |--examples 14 | | | |--src 15 | | | |- Bar.c 16 | | | |- Bar.h 17 | | |--Foo 18 | | | |- Foo.c 19 | | | |- Foo.h 20 | | |- readme.txt --> THIS FILE 21 | |- platformio.ini 22 | |--src 23 | |- main.c 24 | 25 | Then in `src/main.c` you should use: 26 | 27 | #include 28 | #include 29 | 30 | // rest H/C/CPP code 31 | 32 | PlatformIO will find your libraries automatically, configure preprocessor's 33 | include paths and build them. 34 | 35 | More information about PlatformIO Library Dependency Finder 36 | - http://docs.platformio.org/en/stable/librarymanager/ldf.html 37 | -------------------------------------------------------------------------------- /scripts/gen_version.py: -------------------------------------------------------------------------------- 1 | # Generate the Version.h file 2 | # Stitches together various bits of version information from the environment 3 | 4 | import subprocess 5 | import os 6 | 7 | # This was the value used in the static Version.h. It is unclear what merits 8 | # an increment, so it is being included unchanged. 9 | release = "0.2.4" 10 | 11 | # Get the name of the "nearest" tag (decorated with revision information if 12 | # changes have happened since that tag) 13 | # See the man page of git-describe for more details 14 | tag_name = ( 15 | subprocess.check_output(["git", "describe", "--always"]) 16 | .strip() 17 | .decode("utf-8") 18 | ) 19 | 20 | # git revision 21 | git_rev = ( 22 | subprocess.check_output(["git", "rev-parse", "--short", "HEAD"]) 23 | .strip() 24 | .decode("utf-8") 25 | ) 26 | 27 | 28 | 29 | template = f""" 30 | #pragma once 31 | /****************************************************************************** 32 | *** **** WARNING **** **** 33 | 34 | This file is auto-generated. Any changes made here will be destroyed during 35 | the next build. To make persistent changes, edit the template in 36 | /scripts/gen_version.py 37 | ******************************************************************************/ 38 | 39 | namespace Config {{ 40 | namespace Version {{ 41 | constexpr auto release = "{release}"; 42 | constexpr auto git_tag = "{tag_name}"; 43 | constexpr auto git_rev = "{git_rev}"; 44 | }} 45 | }}; 46 | """ 47 | 48 | with open('src/Version.h', 'w') as f: 49 | f.write(template) 50 | -------------------------------------------------------------------------------- /scripts/get_port.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import platform 4 | Import("env") 5 | 6 | system = platform.system() 7 | if system == "Darwin": 8 | # I'll leave it up to @thorrak to figure out how to 9 | # lay this out. 10 | env["UPLOAD_PORT"] = "/dev/cu.usbserial-*" 11 | # env["UPLOAD_PORT"] = "/dev/cu.wch*" 12 | elif system == "Windows": 13 | # Windows users don't need no silly declarations 14 | # port = "COM*" 15 | # usbc = "COM*" 16 | pass 17 | elif system == "Linux": 18 | # port = "/dev/cu.usbserial-*" 19 | # usbc = "/dev/cu.wch*" 20 | pass 21 | else: 22 | pass 23 | -------------------------------------------------------------------------------- /src/Actuator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Matthew McGowan 3 | * Copyright 2013 BrewPi/Elco Jacobs. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #include "Brewpi.h" 22 | #include "Actuator.h" 23 | -------------------------------------------------------------------------------- /src/Actuator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Matthew McGowan 3 | * Copyright 2013 BrewPi/Elco Jacobs. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "Brewpi.h" 24 | #include "FastDigitalPin.h" 25 | 26 | #define ACTUATOR_VIRTUAL 1 27 | 28 | #if ACTUATOR_VIRTUAL 29 | #define ACTUATOR_METHOD virtual 30 | #define ACTUATOR_METHOD_IMPL =0 31 | #define ACTUATOR_BASE_CLASS_DECL : public Actuator 32 | #else 33 | #define ACTUATOR_METHOD inline 34 | #define ACTUATOR_METHOD_IMPL {} 35 | #define ACTUATOR_BASE_CLASS_DECL 36 | #endif 37 | 38 | 39 | /** 40 | * An actuator simply turns something on or off. 41 | */ 42 | class Actuator 43 | { 44 | public: 45 | /** 46 | * Set the state of the actuator 47 | * 48 | * @param active - New state 49 | */ 50 | ACTUATOR_METHOD void setActive(bool active) ACTUATOR_METHOD_IMPL; 51 | 52 | /** 53 | * Check if current actuator state is active 54 | */ 55 | ACTUATOR_METHOD bool isActive() ACTUATOR_METHOD_IMPL; 56 | #if ACTUATOR_VIRTUAL 57 | virtual ~Actuator() {} 58 | #endif 59 | 60 | }; 61 | 62 | /** 63 | * An actuator that simply remembers the set value. 64 | * This is primary used for testing. 65 | */ 66 | class ValueActuator ACTUATOR_BASE_CLASS_DECL 67 | { 68 | public: 69 | ValueActuator() : state(false) {} 70 | ValueActuator(bool initial) : state(initial) {} 71 | 72 | ACTUATOR_METHOD void setActive(bool active) { state = active; } 73 | ACTUATOR_METHOD bool isActive() { return state; } 74 | 75 | private: 76 | bool state; 77 | }; 78 | 79 | -------------------------------------------------------------------------------- /src/ActuatorArduinoPin.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Brewpi.h" 3 | #include "Pins.h" 4 | #include "ActuatorArduinoPin.h" 5 | -------------------------------------------------------------------------------- /src/ActuatorArduinoPin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: ArduinoActuator.h 3 | * Author: mat 4 | * 5 | * Created on 19 August 2013, 20:32 6 | */ 7 | 8 | #pragma once 9 | 10 | #include "Actuator.h" 11 | 12 | //template 13 | //class DigitalConstantPinActuator ACTUATOR_BASE_CLASS_DECL 14 | //{ 15 | // private: 16 | // bool active; 17 | // 18 | // public: 19 | // DigitalConstantPinActuator() : active(false) 20 | // { 21 | // setActive(false); 22 | // fastPinMode(pin, OUTPUT); 23 | // } 24 | // 25 | // inline ACTUATOR_METHOD void setActive(bool active) { 26 | // this->active = active; 27 | // fastDigitalWrite(pin, active^invert ? HIGH : LOW); 28 | // } 29 | // 30 | // bool isActive() { return active; } 31 | // 32 | //}; 33 | 34 | class DigitalPinActuator ACTUATOR_BASE_CLASS_DECL 35 | { 36 | private: 37 | bool invert; 38 | uint8_t pin; 39 | bool active; 40 | public: 41 | DigitalPinActuator(uint8_t pin, bool invert) { 42 | this->invert = invert; 43 | this->pin = pin; 44 | setActive(false); 45 | pinMode(pin, OUTPUT); 46 | } 47 | 48 | inline ACTUATOR_METHOD void setActive(bool active_setting) { 49 | this->active = active_setting; 50 | digitalWrite(pin, active_setting^invert ? HIGH : LOW); 51 | } 52 | 53 | bool isActive() { return active; } 54 | }; 55 | -------------------------------------------------------------------------------- /src/ActuatorAutoOff.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Matthew McGowan 3 | * Copyright 2013 BrewPi/Elco Jacobs. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "Actuator.h" 24 | #include "Ticks.h" 25 | 26 | /** 27 | * An Actuator wrapper that automaically turns the wrapped Actuator off after 28 | * an elapsed timeout 29 | */ 30 | class AutoOffActuator : public Actuator { 31 | 32 | public: 33 | /** 34 | * Constructor. 35 | * 36 | * @param timeout - Number of seconds to stay on after activated 37 | * @param target - Acutuator to manage 38 | */ 39 | AutoOffActuator(uint16_t timeout, Actuator* target) { 40 | this->timeout = timeout; 41 | this->target = target; 42 | } 43 | 44 | /** 45 | * \brief Set the actuator state 46 | * 47 | * @param active - New state 48 | * @see Actuator::setActive() 49 | */ 50 | void setActive(bool active) 51 | { 52 | this->active = active; 53 | target->setActive(active); 54 | if (active) 55 | lastActiveTime = ticks.seconds(); 56 | } 57 | 58 | /** 59 | * \brief Get actuator current state 60 | */ 61 | bool isActive() { 62 | return active; //target->isActive(); - this takes 20 bytes more 63 | } 64 | 65 | /** 66 | * \brief Update the actuator state. 67 | * If the timeout period has elapsed, sets the state to false. 68 | */ 69 | void update() { 70 | if (ticks.timeSince(lastActiveTime)>=timeout) 71 | setActive(false); 72 | } 73 | 74 | private: 75 | uint16_t lastActiveTime; //!< Tick count when the actuator was last made active. 76 | uint16_t timeout; //!< Length of time that the actuator should be enabled before turning off. 77 | Actuator* target; //!< Target Actuator that is being controlled. 78 | 79 | /** 80 | * \brief Current actuator state. 81 | * This effectively duplicates the state that is in the target Actuator, but 82 | * by keeping value here we avoid call overhead to get that value. 83 | */ 84 | bool active; 85 | }; 86 | -------------------------------------------------------------------------------- /src/ActuatorTPLink.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Brewpi.h" 3 | #include "Pins.h" 4 | #include "ActuatorTPLink.h" 5 | #include "tplink/TPLinkScanner.h" 6 | 7 | 8 | 9 | TPLinkActuator::TPLinkActuator(const char * deviceMAC, const char * childID) { 10 | strcpy(device_mac, deviceMAC); 11 | strcpy(child_id, childID); 12 | } 13 | 14 | void TPLinkActuator::setActive(bool active) { 15 | TPLinkPlug *tp; 16 | 17 | tp = tp_link_scanner.get_tplink_plug(device_mac, child_id); 18 | 19 | if(!tp) // Unable to find the actuator in the list, we can't set active. 20 | return; 21 | 22 | if(active && !isActive()) 23 | tp->set_on(); 24 | else if(!active && isActive()) 25 | tp->set_off(); 26 | } 27 | 28 | bool TPLinkActuator::isActive() { 29 | TPLinkPlug *tp; 30 | 31 | tp = tp_link_scanner.get_tplink_plug(device_mac, child_id); 32 | 33 | if(!tp) // Unable to find the actuator in the list, lets assume it's turned off 34 | return false; 35 | 36 | return tp->last_read_on; 37 | } 38 | -------------------------------------------------------------------------------- /src/ActuatorTPLink.h: -------------------------------------------------------------------------------- 1 | #ifndef BREWPI_ESP_ACTUATORTPLINK_H 2 | #define BREWPI_ESP_ACTUATORTPLINK_H 3 | 4 | #include "Brewpi.h" 5 | #include "Actuator.h" 6 | // #include "tplink/TPLinkScanner.h" 7 | #include "PiLink.h" 8 | 9 | /** 10 | * An actuator that operates by communicating with a TPLink Kasa Smart Switch device. 11 | * 12 | */ 13 | class TPLinkActuator : public Actuator 14 | { 15 | public: 16 | 17 | TPLinkActuator(const char * deviceMAC, const char * childID); 18 | 19 | void setActive(bool active); 20 | 21 | bool isActive(); 22 | 23 | 24 | 25 | private: 26 | char device_mac[18]; 27 | char child_id[3]; 28 | }; 29 | 30 | #endif -------------------------------------------------------------------------------- /src/Brewpi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | /** 24 | * \file Brewpi.h 25 | * 26 | * \brief Defines global config for the brewpi project. 27 | * 28 | * This file is included in every file in the project to ensure conditional 29 | * compilation directives are recognized. 30 | * 31 | * ConfigDefault.h contains the default settings, and produces a standard Hex 32 | * file. To customize the build, users may add settings to Config.h, or define 33 | * symbols in the project. 34 | */ 35 | 36 | // have to use two levels of macro expansion to convert a symbol to a string. see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html 37 | #define stringify(s) _stringifyDo(s) 38 | #define _stringifyDo(s) #s 39 | 40 | 41 | // Most pins are only conditionally defined here, allowing definitions to be provided in Config.h for 42 | // local overrides 43 | #define BREWPI_SHIELD_DIY 0 44 | #define BREWPI_SHIELD_REV_A 1 45 | #define BREWPI_SHIELD_REV_C 2 46 | 47 | #define BREWPI_BOARD_LEONARDO 'l' 48 | #define BREWPI_BOARD_STANDARD 's' 49 | #define BREWPI_BOARD_MEGA 'm' 50 | #define BREWPI_BOARD_UNKNOWN '?' 51 | #define BREWPI_BOARD_ESP8266 'e' 52 | #define BREWPI_BOARD_ESP32 '3' 53 | #define BREWPI_BOARD_ESP32C3 'c' 54 | #define BREWPI_BOARD_ESP32S2 '2' 55 | 56 | 57 | #include "Config.h" 58 | #include "ConfigDefault.h" 59 | 60 | #include 61 | 62 | #include "Actuator.h" 63 | #include "Logger.h" 64 | 65 | extern ValueActuator alarm_actuator; 66 | extern bool toggleBacklight; // To allow us to toggle the backlight 67 | 68 | -------------------------------------------------------------------------------- /src/BrewpiStrings.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #include "Brewpi.h" 22 | #include "BrewpiStrings.h" 23 | 24 | // some useful strings 25 | const char STR_FMT_S_RAM[] PROGMEM = "%s"; // RAM string 26 | const char STR_FMT_S_PROGMEM[] PROGMEM = "%S"; // PROGMEM string 27 | const char STR_FMT_D[] PROGMEM = "%d"; 28 | const char STR_FMT_U[] PROGMEM = "%u"; 29 | const char STR_6SPACES[] PROGMEM = " "; 30 | 31 | 32 | 33 | #if !indexOf_inline 34 | int8_t indexOf(const char* s, char c) 35 | { 36 | char c2; 37 | int8_t idx = -1; 38 | while ((c2=s[++idx])) 39 | { 40 | if (c==c2) 41 | return idx; 42 | } 43 | return -1; 44 | } 45 | #endif 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/BrewpiStrings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | extern const char STR_FMT_S_RAM[]; 24 | extern const char STR_FMT_S_PROGMEM[]; 25 | extern const char STR_FMT_U[]; 26 | extern const char STR_FMT_D[]; 27 | extern const char STR_6SPACES[]; 28 | 29 | #define indexOf_inline 0 30 | 31 | #if indexOf_inline 32 | inline int8_t indexOf(const char* s, char c) 33 | { 34 | char c2; 35 | int8_t idx = -1; 36 | while ((c2=s[++idx])) 37 | { 38 | if (c==c2) 39 | return idx; 40 | } 41 | return -1; 42 | } 43 | #else 44 | int8_t indexOf(const char* s, char c); 45 | #endif 46 | -------------------------------------------------------------------------------- /src/Buzzer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Buzzer.cpp 3 | * 4 | * Copyright 2012-2013 BrewPi. 5 | * 6 | * This file is part of BrewPi. 7 | * 8 | * BrewPi is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * BrewPi is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with BrewPi. If not, see . 20 | */ 21 | 22 | 23 | #include "Brewpi.h" 24 | #include "Ticks.h" 25 | #include "Pins.h" 26 | #include "Buzzer.h" 27 | 28 | // TODO - Implement 29 | 30 | #if BREWPI_BUZZER 31 | #include 32 | #include "FastDigitalPin.h" 33 | 34 | #if (alarmPin != 3) 35 | #error "Check PWM settings when you want to use a different pin for the alarm" 36 | #endif 37 | 38 | #if BREWPI_BOARD == BREWPI_BOARD_LEONARDO 39 | #define BUZZER_TIMER_REG TCCR0A 40 | #define BUZZER_TIMER_REG_FLAG COM0B1 41 | #define BUZZER_TIMER_REG_INIT (void); 42 | #elif BREWPI_BOARD == BREWPI_BOARD_STANDARD 43 | #define BUZZER_TIMER_REG TCCR2A 44 | #define BUZZER_TIMER_REG_FLAG COM2B1 45 | #elif BREWPI_BOARD == BREWPI_BOARD_MEGA 46 | #define BUZZER_TIMER_REG TCCR3A 47 | #define BUZZER_TIMER_REG_FLAG COM3C1 48 | #endif 49 | 50 | #define BEEP_ON() bitSet(BUZZER_TIMER_REG,BUZZER_TIMER_REG_FLAG); 51 | #define BEEP_OFF() bitClear(BUZZER_TIMER_REG,BUZZER_TIMER_REG_FLAG); 52 | 53 | void Buzzer::init(){ 54 | // set up square wave PWM for buzzer 55 | fastPinMode(alarmPin,OUTPUT); 56 | 57 | #if BREWPI_BOARD == BREWPI_BOARD_LEONARDO 58 | // Arduino Leonardo, no further setup needed - timer already active 59 | #elif BREWPI_BOARD == BREWPI_BOARD_STANDARD 60 | // Arduino UNO, buzzer is on OC2B 61 | TCCR2A = (1<isActive()) { 77 | ValueActuator::setActive(active); 78 | if (active) { 79 | BEEP_ON(); 80 | } 81 | else { 82 | BEEP_OFF(); 83 | } 84 | } 85 | } 86 | 87 | void Buzzer::beep(uint8_t numBeeps, uint16_t duration){ 88 | for(uint8_t beepCount = 0; beepCount. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "Brewpi.h" 23 | #include "Actuator.h" 24 | 25 | #if BREWPI_BUZZER 26 | class Buzzer : public ValueActuator 27 | { 28 | public: 29 | Buzzer(){}; 30 | ~Buzzer(){}; 31 | 32 | void init(); 33 | 34 | /** 35 | * Performs a number of beeps synchronously. 36 | * @param numBeeps The number of beeps to emit 37 | * @param duration the duration of each beep 38 | */ 39 | void beep(uint8_t numBeeps, uint16_t duration); 40 | 41 | void setActive(bool active); 42 | 43 | }; 44 | 45 | extern Buzzer buzzer; 46 | #endif 47 | -------------------------------------------------------------------------------- /src/CommandProcessor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * Copyright 2020 Scott Peshak 5 | * 6 | * This file is part of BrewPi. 7 | * 8 | * BrewPi is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * BrewPi is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with BrewPi. If not, see . 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | /** 26 | * \brief Functions that implement protocol commands 27 | */ 28 | struct CommandProcessor { 29 | public: 30 | static void receiveCommand(); 31 | 32 | private: 33 | static void invalidCommand(const char inByte); 34 | static void commandNotImplemented(const char command, const String message); 35 | static void versionInfo(); 36 | 37 | static void sendControlSettings(); 38 | static void sendControlConstants(); 39 | static void sendControlVariables(); 40 | static void sendExtendedSettings(); 41 | 42 | static void setDefaultConstants(); 43 | static void setDefaultSettings(); 44 | 45 | static void processSettingsJson(); 46 | static void processExtendedSettingsJson(); 47 | 48 | static void printTemperatures(); 49 | static void printRawTemperatures(); 50 | 51 | // Hardware state 52 | static void setAlarmState(bool enabled); 53 | static void listDevices(); 54 | static void listHardware(); 55 | static void resetWiFi(); 56 | static void wifiInfo(); 57 | static void parseDeviceDefinition(); 58 | 59 | // LCD 60 | static void toggleBacklight(); 61 | static void getLcdContent(); 62 | 63 | // EEPROM 64 | static void initEeprom(); 65 | 66 | // Device name 67 | static void printDeviceNames(); 68 | static void setDeviceNames(); 69 | 70 | static void processSettingKeypair(JsonPair); 71 | }; 72 | -------------------------------------------------------------------------------- /src/DS2413.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Matthew McGowan 3 | * Copyright 2013 BrewPi/Elco Jacobs. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #if BREWPI_DS2413 22 | #include "Brewpi.h" 23 | 24 | #include 25 | 26 | #include "DS2413.h" 27 | 28 | 29 | 30 | /* 31 | * Read all values at once, both current state and sensed values. The read performs data-integrity checks. 32 | * Returns a negative result if the device cannot be read successfully within the given number of tries. 33 | * The lower 4-bits are the values as described under PIO ACCESSS READ [F5h] in the ds2413 datasheet: 34 | * b0: PIOA state 35 | * b1: PIOA output latch state 36 | * b2: PIOB state 37 | * b3: PIOB output latch state 38 | */ 39 | byte DS2413::accessRead(uint8_t maxTries) /* const */ 40 | { 41 | #define ACCESS_READ 0xF5 42 | 43 | oneWire->reset(); 44 | oneWire->select(address); 45 | oneWire->write(ACCESS_READ); 46 | 47 | bool success = false; 48 | uint8_t data; 49 | do 50 | { 51 | data = oneWire->read(); 52 | success = (data>>4)==(!data&0xF); 53 | data &= 0xF; 54 | } while (!success && maxTries-->0); 55 | 56 | oneWire->reset(); 57 | return success ? data : data|0x80; 58 | } 59 | 60 | /* 61 | * Writes the state of all PIOs in one operation. 62 | * /param b pio data - PIOA is bit 0 (lsb), PIOB is bit 1 63 | * /param maxTries the maximum number of attempts before giving up. 64 | * /return true on success 65 | */ 66 | bool DS2413::accessWrite(uint8_t b, uint8_t maxTries) 67 | { 68 | #define ACCESS_WRITE 0x5A 69 | #define ACK_SUCCESS 0xAA 70 | #define ACK_ERROR 0xFF 71 | 72 | b |= 0xFC; /* Upper 6 bits should be set to 1's */ 73 | uint8_t ack = 0; 74 | do 75 | { 76 | oneWire->reset(); 77 | oneWire->select(address); 78 | oneWire->write(ACCESS_WRITE); 79 | oneWire->write(b); 80 | 81 | /* data is sent again, inverted to guard against transmission errors */ 82 | oneWire->write(~b); 83 | /* Acknowledgement byte, 0xAA for success, 0xFF for failure. */ 84 | ack = oneWire->read(); 85 | 86 | if (ack==ACK_SUCCESS) 87 | oneWire->read(); // status byte sent after ack 88 | 89 | //out.print("tries "); out.print(maxTries); out.print(" ack ");out.print(ack, HEX);out.print(" newValues ");out.print(newSettings, HEX); 90 | //out.println(); 91 | } while (ack!=ACK_SUCCESS && maxTries-->0); 92 | 93 | oneWire->reset(); 94 | return ack==ACK_SUCCESS; 95 | } 96 | 97 | #endif -------------------------------------------------------------------------------- /src/DallasTempNG.cpp: -------------------------------------------------------------------------------- 1 | #include "DallasTempNG.h" 2 | 3 | typedef uint8_t ScratchPad[9]; 4 | 5 | // Scratchpad locations 6 | #define TEMP_LSB 0 7 | #define TEMP_MSB 1 8 | #define HIGH_ALARM_TEMP 2 9 | #define LOW_ALARM_TEMP 3 10 | #define CONFIGURATION 4 11 | #define INTERNAL_BYTE 5 12 | #define COUNT_REMAIN 6 13 | #define COUNT_PER_C 7 14 | #define SCRATCHPAD_CRC 8 15 | 16 | 17 | bool detectedReset(DallasTemperature &sensor, const uint8_t* scratchPad) { 18 | bool reset = (scratchPad[HIGH_ALARM_TEMP]==0); 19 | return reset; 20 | } 21 | 22 | bool initConnection(DallasTemperature &sensor, const uint8_t* deviceAddress) { 23 | ScratchPad scratchPad; 24 | 25 | if (!sensor.isConnected(deviceAddress, scratchPad)) { 26 | return false; 27 | } 28 | 29 | // assume the sensor has just been powered on. So this should only be called on initializtion, or 30 | // after a device was disconnected. 31 | if (scratchPad[HIGH_ALARM_TEMP]) { // conditional to avoid wear on eeprom. 32 | scratchPad[HIGH_ALARM_TEMP] = 0; 33 | sensor.writeScratchPad(deviceAddress, scratchPad); 34 | sensor.saveScratchPad(deviceAddress); // save to eeprom 35 | 36 | // check if the write was successful (HIGH_ALARAM_TEMP == 0) 37 | if (!sensor.isConnected(deviceAddress, scratchPad) || !detectedReset(sensor, scratchPad)) 38 | return false; 39 | } 40 | 41 | scratchPad[HIGH_ALARM_TEMP]=1; 42 | sensor.writeScratchPad(deviceAddress, scratchPad); // don't save to eeprom, so that it reverts to 0 on reset 43 | // from this point on, if we read a scratchpad with a 0 value in HIGH_ALARM (detectedReset() returns true) 44 | // it means the device has reset or the previous write of the scratchpad above was unsuccessful. 45 | // Either way, initConnection() should be called again 46 | return true; 47 | } 48 | 49 | 50 | int16_t getTempRaw(DallasTemperature &sensor, const uint8_t* deviceAddress) 51 | { 52 | ScratchPad scratchPad; 53 | if (sensor.isConnected(deviceAddress, scratchPad) && !detectedReset(sensor, scratchPad)) 54 | return sensor.getTemp(deviceAddress) >> 3; 55 | return DEVICE_DISCONNECTED_RAW; // use a value that the sensor could not ordinarily measure 56 | } 57 | -------------------------------------------------------------------------------- /src/DallasTempNG.h: -------------------------------------------------------------------------------- 1 | #ifndef BREWPI_ESP_DALLAS_TEMP_NG_H 2 | #define BREWPI_ESP_DALLAS_TEMP_NG_H 3 | 4 | #include 5 | #include 6 | 7 | bool initConnection(DallasTemperature &sensor, const uint8_t* deviceAddress); 8 | int16_t getTempRaw(DallasTemperature &sensor, const uint8_t* deviceAddress); 9 | 10 | #endif // BREWPI_ESP_DALLAS_TEMP_NG_H -------------------------------------------------------------------------------- /src/DeviceNameManager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Scott Peshak 3 | * Copyright 2013 BrewPi/Elco Jacobs. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | 22 | #include "DeviceNameManager.h" 23 | #include "ESPEepromAccess.h" // Includes filesystem headers/definition 24 | 25 | /** 26 | * \brief Set a human readable name for a device. 27 | * \param device - The identifier for the device, most commonly the OneWire device address (in hex) 28 | * \param name - The name to set 29 | */ 30 | void DeviceNameManager::setDeviceName(const char* device, const char* name) 31 | { 32 | char filename[32]; 33 | DeviceNameManager::deviceNameFilename(filename, device); 34 | 35 | File f = FILESYSTEM.open(filename, "w"); 36 | 37 | if (f) { 38 | f.print(name); 39 | f.close(); 40 | } 41 | } 42 | 43 | 44 | /** 45 | * \brief Get the human readable name for a device. 46 | * 47 | * If no name has been registered, the device ID will be returned. 48 | * \param device - The identifier for the device, most commonly the OneWire device address (in hex) 49 | * \return The registered device name, or if none is set, the provided device ID 50 | */ 51 | String DeviceNameManager::getDeviceName(const char* device) { 52 | char filename[32]; 53 | DeviceNameManager::deviceNameFilename(filename, device); 54 | 55 | if (FILESYSTEM.exists(filename)) { 56 | File f = FILESYSTEM.open(filename, "r"); 57 | if (f) { 58 | String res = f.readString(); 59 | f.close(); 60 | return res; 61 | } 62 | } 63 | 64 | return device; 65 | } 66 | 67 | 68 | /** 69 | * \brief Get the Filename that contains the device human name metadata for a given device. 70 | * \param device - The identifier for the device, most commonly the OneWire device address (in hex) 71 | */ 72 | inline void DeviceNameManager::deviceNameFilename(char* filename, const char* device) { 73 | strcpy(filename, DeviceNameManager::filenamePrefix); 74 | strncat(filename, device, 32 - DeviceNameManager::prefixLength()); 75 | } 76 | 77 | 78 | /** 79 | * \brief Prefix used when building device name filenames 80 | * 81 | * This helps disambiguate the name files from other data, and makes it easier 82 | * to produce a list of named probes. 83 | */ 84 | const char DeviceNameManager::filenamePrefix[] = "/dn/"; 85 | 86 | /** 87 | * \brief Calculate length of DeviceNameManager::filenamePrefix 88 | * 89 | * This is done as a constexpr so it can be calculated at compile time 90 | */ 91 | constexpr int DeviceNameManager::prefixLength() { 92 | return strlen(DeviceNameManager::filenamePrefix); 93 | } 94 | 95 | 96 | /** 97 | * \brief Delete a configured device name 98 | * \param device - The identifier for the device, most commonly the OneWire device address (in hex) 99 | */ 100 | void DeviceNameManager::deleteDeviceName(const char* device) { 101 | char filename[32]; 102 | DeviceNameManager::deviceNameFilename(filename, device); 103 | 104 | FILESYSTEM.remove(filename); 105 | } 106 | 107 | 108 | #if defined(ESP32) 109 | /** 110 | * \brief Get list of configured device names 111 | */ 112 | void DeviceNameManager::enumerateDeviceNames(JsonDocument& doc) { 113 | File root = FILESYSTEM.open(filenamePrefix); 114 | 115 | File file = root.openNextFile(); 116 | 117 | while(file){ 118 | DeviceName dn = filenameToDeviceName(file.name()); 119 | doc[dn.device] = dn.name; 120 | 121 | // Move to the next file 122 | file = root.openNextFile(); 123 | } 124 | } 125 | 126 | #else 127 | 128 | /** 129 | * \brief Get list of configured device names 130 | */ 131 | void DeviceNameManager::enumerateDeviceNames(JsonDocument& doc) { 132 | // This is ESP8266 only 133 | Dir dir = FILESYSTEM.openDir(filenamePrefix); 134 | 135 | while (dir.next()) { 136 | DeviceName dn = filenameToDeviceName(dir.fileName()); 137 | doc[dn.device] = dn.name; 138 | } 139 | } 140 | #endif 141 | 142 | 143 | /** 144 | * \brief Given a filename, get a DeviceName 145 | * 146 | * \param filename 147 | */ 148 | DeviceName DeviceNameManager::filenameToDeviceName(String filename) { 149 | // strip the prefix off 150 | filename = filename.substring(prefixLength()); 151 | 152 | return DeviceName(filename, getDeviceName(filename.c_str())); 153 | } 154 | -------------------------------------------------------------------------------- /src/DeviceNameManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Scott Peshak 3 | * Copyright 2013 BrewPi/Elco Jacobs. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "Brewpi.h" 24 | #include 25 | 26 | /** 27 | * \brief Tuple of device name and ID 28 | */ 29 | struct DeviceName 30 | { 31 | String name; //!< Human readable name 32 | String device; //!< Device ID 33 | 34 | DeviceName(String device, String name): name(name), device(device){} 35 | }; 36 | 37 | 38 | 39 | /** 40 | * \brief Class to manage human readable names for devices 41 | */ 42 | class DeviceNameManager 43 | { 44 | public: 45 | static void setDeviceName(const char* device, const char* name); 46 | static String getDeviceName(const char* device); 47 | static void deleteDeviceName(const char* device); 48 | 49 | static void enumerateDeviceNames(JsonDocument& doc); 50 | 51 | private: 52 | static void deviceNameFilename(char* filename, const char* device); 53 | static DeviceName filenameToDeviceName(String filename); 54 | 55 | static const char filenamePrefix[]; 56 | static constexpr int prefixLength(); 57 | }; 58 | -------------------------------------------------------------------------------- /src/Display.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * 4 | * This file is part of BrewPi. 5 | * 6 | * BrewPi is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later v7ersion. 10 | * 11 | * BrewPi is dist7ributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BrewPi. If not, see . 18 | */ 19 | 20 | #include "Brewpi.h" 21 | #include 22 | 23 | #include "Display.h" 24 | 25 | 26 | #if DISPLAY_POLYMORPHIC 27 | Display::~Display() { } 28 | #endif 29 | 30 | -------------------------------------------------------------------------------- /src/Display.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | /** 24 | * \defgroup display LCD Display 25 | * \brief Support for different LCD display types 26 | * 27 | * \addtogroup display 28 | * @{ 29 | * 30 | * \file Display.h 31 | * \brief To use the display, include this file. 32 | * 33 | * It takes care of setting DisplayType to the appropriate type of display 34 | * according to the compile-time config. 35 | */ 36 | 37 | #include "DisplayBase.h" 38 | #include "DisplayLcd.h" 39 | 40 | typedef LcdDisplay DisplayType; 41 | 42 | 43 | extern DisplayType DISPLAY_REF display; 44 | 45 | /** @} */ 46 | -------------------------------------------------------------------------------- /src/DisplayLcd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * 4 | * This file is part of BrewPi. 5 | * 6 | * BrewPi is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BrewPi is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BrewPi. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "Brewpi.h" 23 | #include "DisplayBase.h" 24 | 25 | // If BREWPI_TFT is set, we're going to use the DisplayTFT headers instead 26 | #ifdef BREWPI_TFT 27 | #include "DisplayTFT.h" 28 | #else 29 | 30 | /* 31 | * \addtogroup display 32 | * @{ 33 | */ 34 | 35 | #if BREWPI_EMULATE || !BREWPI_LCD 36 | #include "NullLcdDriver.h" 37 | typedef NullLcdDriver LcdDriver; 38 | #elif defined(BREWPI_OLED) 39 | #include "OLEDFourBit.h" 40 | typedef OLEDFourBit LcdDriver; 41 | #elif defined(BREWPI_IIC) 42 | #include "IicLcd.h" 43 | typedef IIClcd LcdDriver; 44 | #elif defined(BREWPI_SHIFT_LCD) 45 | #include "SpiLcd.h" 46 | typedef SpiLcd LcdDriver; 47 | #else 48 | #error "Wrong LCD type! Select one in Config.h." 49 | #endif 50 | 51 | 52 | /** 53 | * \brief LCD Display Content 54 | * 55 | * This class handles the content of the LCD. It dispatches to the various 56 | * hardware driver implementations to actually display the content 57 | */ 58 | class LcdDisplay DISPLAY_SUPERCLASS 59 | { 60 | public: 61 | // initializes the lcd display 62 | DISPLAY_METHOD void init(); 63 | 64 | /** 65 | * Print all display content 66 | */ 67 | DISPLAY_METHOD void printAll() { 68 | printStationaryText(); 69 | printState(); 70 | printAllTemperatures(); 71 | printMode(); 72 | updateBacklight(); 73 | } 74 | 75 | DISPLAY_METHOD void printAllTemperatures(); 76 | 77 | // print the stationary text on the lcd. 78 | DISPLAY_METHOD void printStationaryText(); 79 | 80 | // print mode on the right location on the first line, after Mode: 81 | DISPLAY_METHOD void printMode(); 82 | 83 | DISPLAY_METHOD void setDisplayFlags(uint8_t newFlags); 84 | DISPLAY_METHOD uint8_t getDisplayFlags() { return flags; }; 85 | 86 | // print beer temperature at the right place on the display 87 | DISPLAY_METHOD void printBeerTemp(); 88 | 89 | // print beer temperature setting at the right place on the display 90 | DISPLAY_METHOD void printBeerSet(); 91 | 92 | // print fridge temperature at the right place on the display 93 | DISPLAY_METHOD void printFridgeTemp(); 94 | 95 | // print fridge temperature setting at the right place on the display 96 | DISPLAY_METHOD void printFridgeSet(); 97 | 98 | // print the current state on the last line of the LCD 99 | DISPLAY_METHOD void printState(); 100 | 101 | DISPLAY_METHOD void getLine(uint8_t lineNumber, char *buffer) { lcd.getLine(lineNumber, buffer); } 102 | 103 | DISPLAY_METHOD void printAt_P(uint8_t x, uint8_t y, const char *text); 104 | 105 | DISPLAY_METHOD void setBufferOnly(bool bufferOnly) 106 | { 107 | lcd.setBufferOnly(bufferOnly); 108 | } 109 | 110 | DISPLAY_METHOD void resetBacklightTimer() { lcd.resetBacklightTimer(); } 111 | DISPLAY_METHOD void updateBacklight() { lcd.updateBacklight(); } 112 | 113 | // print a temperature 114 | DISPLAY_METHOD void printTemperature(temperature temp); 115 | DISPLAY_METHOD void printTemperatureAt(uint8_t x, uint8_t y, temperature temp); 116 | 117 | // print degree sign + C/F 118 | DISPLAY_METHOD void printDegreeUnit(uint8_t x, uint8_t y); 119 | 120 | DISPLAY_METHOD void printAt(uint8_t x, uint8_t y, char *text); 121 | 122 | #ifdef ESP8266_WiFi 123 | DISPLAY_METHOD void printWiFiStartup(); 124 | DISPLAY_METHOD void printWiFi(); 125 | DISPLAY_METHOD void printWiFi_setup(); 126 | DISPLAY_METHOD void printWiFiConnect(); 127 | #endif 128 | 129 | #ifdef HAS_BLUETOOTH 130 | DISPLAY_METHOD void printBluetoothStartup(); 131 | #endif 132 | 133 | DISPLAY_METHOD void clear(); 134 | 135 | 136 | private: 137 | DISPLAY_FIELD LcdDriver lcd; 138 | DISPLAY_FIELD uint8_t stateOnDisplay; 139 | DISPLAY_FIELD uint8_t flags; 140 | }; 141 | 142 | #endif 143 | /** @} */ 144 | -------------------------------------------------------------------------------- /src/ESPEepromAccess.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 John Beeler 3 | * 4 | * This is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this file. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #if defined(ESP8266) 21 | #define FILESYSTEM LittleFS 22 | #include 23 | 24 | #elif defined(ESP32S2) 25 | // #define FILESYSTEM LittleFS 26 | // #include 27 | #define FILESYSTEM SPIFFS 28 | #include 29 | 30 | 31 | #elif defined(ESP32) 32 | #define FILESYSTEM SPIFFS 33 | #include 34 | 35 | #else 36 | #error "Not supported!" 37 | #endif 38 | 39 | #include "EepromStructs.h" 40 | #include "Brewpi.h" // Only needed for Config:: below 41 | 42 | 43 | //TODO - Clean this up 44 | class ESPEepromAccess 45 | { 46 | private: 47 | static bool doesFileExist(String target_name) { 48 | return FILESYSTEM.exists(target_name); 49 | } 50 | 51 | public: 52 | 53 | static void zapData() { 54 | // This gets a bit tricky -- we can't just do FS.format because that would wipe out the mDNS name 55 | int i; 56 | if(doesFileExist(ControlConstants::filename)) FILESYSTEM.remove(ControlConstants::filename); 57 | if(doesFileExist(ControlSettings::filename)) FILESYSTEM.remove(ControlSettings::filename); 58 | 59 | char buf[20]; 60 | for(i=0;i 3 | 4 | /** 5 | * \file ESP_BP_WiFi.h 6 | * 7 | * \defgroup wifi WiFi Configuration & Management 8 | * \brief WiFi configuration functions 9 | * 10 | * Various helper functions for interacting with the WiFi configuration. 11 | * 12 | * \addtogroup wifi 13 | * @{ 14 | */ 15 | 16 | // This library always needs to get loaded, as we're going to need to interact with the radio regardless of whether 17 | // we're using WiFi or not. If neither ESP8266 or ESP32 is defined, (properly) do nothing (though this shouldn't 18 | // actually compile for Arduino) 19 | #if defined(ESP8266) 20 | #include // For printing the IP address 21 | #elif defined(ESP32) 22 | #include // For printing the IP address 23 | #endif 24 | 25 | 26 | 27 | /** 28 | * \brief Initialize the WiFi client 29 | * 30 | * If WiFi is enabled, this sets it up. Otherwise, it disconnects the radio. 31 | */ 32 | void initialize_wifi(); 33 | 34 | /** 35 | * \brief Display the WiFi splash screen & trigger reconnection callback. 36 | */ 37 | void display_connect_info_and_create_callback(); 38 | 39 | /** 40 | * \brief Handle incoming WiFi client connections. 41 | * 42 | * This also handles WiFi network reconnects if the network was disconnected. 43 | */ 44 | void wifi_connect_clients(); 45 | 46 | /** 47 | * \brief Initialize the telnet server 48 | */ 49 | void initWifiServer(); 50 | 51 | 52 | /** 53 | * \brief Get current WiFi connection information, in JsonDocument format 54 | * 55 | * \param doc - JsonDocument to populate. 56 | */ 57 | void wifi_connection_info(JsonDocument& doc); 58 | 59 | extern WiFiServer server; 60 | extern WiFiClient serverClient; 61 | 62 | /** @} */ 63 | -------------------------------------------------------------------------------- /src/EepromManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "Brewpi.h" 24 | 25 | #include "ESPEepromAccess.h" 26 | #include "EepromStructs.h" 27 | 28 | 29 | class DeviceConfig; 30 | 31 | 32 | // todo - the Eeprom manager should avoid too frequent saves to the eeprom since it supports 100,000 writes. 33 | class EepromManager { 34 | public: 35 | 36 | EepromManager(); 37 | 38 | /** 39 | * Prepare the eeprom to accept device definitions. For RevA boards, the eeprom is populated with devices for 40 | * beer/fridge temp sensor, and heating,cooling actuators and door switch. 41 | */ 42 | static bool initializeEeprom(); 43 | 44 | /** 45 | * Applies the settings from the eeprom 46 | */ 47 | bool applySettings(); 48 | 49 | 50 | DeviceConfig fetchDevice(uint8_t deviceIndex); 51 | void storeDevice(DeviceConfig& config, uint8_t deviceIndex); 52 | void deleteDeviceWithFunction(DeviceFunction function); 53 | 54 | static uint8_t saveDefaultDevices(); 55 | 56 | #ifdef ESP8266_WiFi 57 | static String fetchmDNSName(); 58 | static void savemDNSName(String mdns_id); 59 | #endif 60 | 61 | 62 | private: 63 | bool cache_loaded = false; 64 | void loadDevicesToCache(); 65 | DeviceConfig cached_devices[Config::EepromFormat::MAX_DEVICES]; 66 | 67 | }; 68 | 69 | 70 | extern EepromManager eepromManager; 71 | extern ExtendedSettings extendedSettings; 72 | extern UpstreamSettings upstreamSettings; 73 | -------------------------------------------------------------------------------- /src/Emulator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #include "Brewpi.h" 22 | 23 | class MockSerial : public Stream { 24 | public: 25 | void print(char c) {} 26 | void print(const char *c) {} 27 | void printNewLine() {} 28 | void println() {} 29 | int read() { return -1; } 30 | int available() { return -1; } 31 | void begin(unsigned long) {} 32 | size_t write(uint8_t w) { return 1; } 33 | int peek() { return -1; } 34 | void flush(){}; 35 | operator bool() { return true; } 36 | }; 37 | 38 | static MockSerial mockSerial; 39 | -------------------------------------------------------------------------------- /src/FastDigitalPin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #ifndef FAST_DIGITAL_PIN 24 | #define FAST_DIGITAL_PIN 1 25 | #endif 26 | 27 | // compiler optimization required in order to resolve pin numbers to compile time constants. 28 | #define USE_FAST_DIGITAL_PIN FAST_DIGITAL_PIN && __OPTIMIZE__ 29 | 30 | #if USE_FAST_DIGITAL_PIN 31 | #include "DigitalPin.h" 32 | #else 33 | #define fastPinMode pinMode 34 | #define fastDigitalWrite digitalWrite 35 | #define fastDigitalRead digitalRead 36 | #endif 37 | 38 | -------------------------------------------------------------------------------- /src/FilterCascaded.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * 4 | * This file is part of BrewPi. 5 | * 6 | * BrewPi is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BrewPi is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BrewPi. If not, see . 18 | */ 19 | 20 | #include "Brewpi.h" 21 | #include "FilterFixed.h" 22 | #include "FilterCascaded.h" 23 | #include 24 | #include 25 | #include "TemperatureFormats.h" 26 | 27 | CascadedFilter::CascadedFilter() { 28 | // default to a b value of 2 29 | setCoefficients(2); 30 | } 31 | 32 | /** 33 | * \brief Set all secition coefficients to a given value 34 | * 35 | * @param bValue new coefficient value 36 | */ 37 | void CascadedFilter::setCoefficients(uint8_t bValue){ 38 | for(uint8_t i=0; i. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "Brewpi.h" 23 | 24 | #include "TemperatureFormats.h" 25 | #include "FilterFixed.h" 26 | 27 | 28 | /** 29 | * \brief Implements a filter that consists of multiple second order sections. 30 | */ 31 | class CascadedFilter { 32 | public: 33 | /** 34 | * \brief Number of filter sections to use 35 | * 36 | * Three filter sections gives excellent filtering, without adding too 37 | * much delay. For 3 sections the stop band attenuation is 3x the single 38 | * section attenuation in dB. The delay is also tripled. 39 | */ 40 | constexpr static int numFilterSections = 3; 41 | 42 | /** 43 | * \brief Filter sections 44 | */ 45 | FixedFilter sections[numFilterSections]; 46 | 47 | public: 48 | CascadedFilter(); 49 | ~CascadedFilter() {} 50 | void init(temperature val); 51 | void setCoefficients(uint8_t bValue); 52 | temperature add(temperature val); 53 | temperature_precise addDoublePrecision(temperature_precise val); 54 | temperature readInput(); 55 | 56 | /** 57 | * \brief Read the output 58 | */ 59 | temperature readOutput(){ 60 | return sections[numFilterSections - 1].readOutput(); // return output of last section 61 | } 62 | temperature_precise readOutputDoublePrecision(); 63 | temperature_precise readPrevOutputDoublePrecision(); 64 | 65 | /** 66 | * \brief Do positive peak detection 67 | */ 68 | temperature detectPosPeak(){ 69 | return sections[numFilterSections - 1].detectPosPeak(); // detect peaks in last section 70 | } 71 | 72 | /** 73 | * \brief Do negative peak detection 74 | */ 75 | temperature detectNegPeak(){ 76 | return sections[numFilterSections - 1].detectNegPeak(); // detect peaks in last section 77 | } 78 | }; 79 | -------------------------------------------------------------------------------- /src/FilterFixed.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * 4 | * This file is part of BrewPi. 5 | * 6 | * BrewPi is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BrewPi is distributed in the hope that it will be useful, 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with BrewPi. If not, see . 15 | */ 16 | #include "Brewpi.h" 17 | #include "FilterFixed.h" 18 | #include 19 | #include 20 | #include "TemperatureFormats.h" 21 | 22 | /** 23 | * \brief Add a temperature value to the filter 24 | * 25 | * @param val - Temp value to add 26 | */ 27 | temperature FixedFilter::add(temperature val){ 28 | temperature_precise returnVal = addDoublePrecision(tempRegularToPrecise(val)); 29 | return tempPreciseToRegular(returnVal); 30 | } 31 | 32 | 33 | /** 34 | * \brief Add a temperature value to the filter 35 | * 36 | * @param val - Temp value to add 37 | */ 38 | temperature_precise FixedFilter::addDoublePrecision(temperature_precise val){ 39 | xv[2] = xv[1]; 40 | xv[1] = xv[0]; 41 | xv[0] = val; 42 | 43 | yv[2] = yv[1]; 44 | yv[1] = yv[0]; 45 | 46 | /* Implementation that prevents overflow as much as possible by order of operations: */ 47 | yv[0] = ((yv[1] - yv[2]) + yv[1]) // expected value + 1* 48 | - (yv[1]>>b) + (yv[2]>>b) + // expected value +0* 49 | + (xv[0]>>a) + (xv[1]>>(a-1)) + (xv[2]>>a) // expected value +(1>>(a-2)) 50 | - (yv[2]>>(a-2)); // expected value -(1>>(a-2)) 51 | 52 | return yv[0]; 53 | } 54 | 55 | 56 | /** 57 | * \brief Initialize the filter 58 | * 59 | * @param val - Initial temp value to seed the filter with 60 | */ 61 | void FixedFilter::init(temperature val){ 62 | xv[0] = val; 63 | xv[0] = tempRegularToPrecise(xv[0]); // 16 extra bits are used in the filter for the fraction part 64 | 65 | xv[1] = xv[0]; 66 | xv[2] = xv[0]; 67 | 68 | yv[0] = xv[0]; 69 | yv[1] = xv[0]; 70 | yv[2] = xv[0]; 71 | } 72 | 73 | /** 74 | * \brief Detect the positive peak 75 | * @return positive peak or INVALID_TEMP when no peak has been found 76 | */ 77 | temperature FixedFilter::detectPosPeak(){ 78 | if(yv[0] < yv[1] && yv[1] >= yv[2]){ 79 | return tempPreciseToRegular(yv[1]); 80 | } 81 | else{ 82 | return INVALID_TEMP; 83 | } 84 | } 85 | 86 | 87 | /** 88 | * \brief Detect the negative peak 89 | * @return negative peak or INVALID_TEMP when no peak has been found 90 | */ 91 | temperature FixedFilter::detectNegPeak(){ 92 | if(yv[0] > yv[1] && yv[1] <= yv[2]){ 93 | return tempPreciseToRegular(yv[1]); 94 | } 95 | else{ 96 | return INVALID_TEMP; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/FilterFixed.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * 4 | * This file is part of BrewPi. 5 | * 6 | * BrewPi is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BrewPi is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BrewPi. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "Brewpi.h" 23 | #include "TemperatureFormats.h" 24 | 25 | /** 26 | * This class implements an IIR low pass filter, with the following frequency response 27 | * 28 | * \f[ 29 | * H(z) = 2^{-a} 30 | * \frac{1 + 2z^{-1} + 1z^{-2}}{1 + (-2 + 2^{-b})z^{-1} + (1-2^{-b} + 4* 2^{-a})z^{-2}} 31 | * \f] 32 | * 33 | * - All filter coefficients are powers of two, so the filter can be efficiently implemented with bit shifts 34 | * - The DC gain is exactly 1. 35 | * - For real poles, and therefore no overshoot, use \f$ a <= 2b+4 \f$. 36 | * - To calculate the poles, you can use this [wolfram alpha 37 | * link](http://www.wolframalpha.com/input/?i=solve+%281++%2B+%28-2+%2B+2^-b%29z^-1++%2B+%281-2^-b+%2B+4*+2^-a%29z^-2%29+%3D+0+where+a+%3D+24+and+b+%3D+10) 38 | * - The filter has a zero at \f$z = -1\f$ 39 | * - For \f$a=2b+4\f$, it has a pole at \f$z = \frac{(2^{b+1}-1)}{2^{b+1}}\f$ 40 | * 41 | * Here are the specifications for a single stage filter, for values \f$a=2b+4\f$ 42 | * The delay time is the time it takes to rise to 0.5 in a step response. 43 | * When cascaded filters are used, multiply the delay time by the number of cascades. 44 | * 45 | * | a | b | Delay Time | 46 | * |---|---|------------| 47 | * | 4 | 0 | 3 | 48 | * | 6 | 1 | 6 | 49 | * | 8 | 2 | 13 | 50 | * | 10 | 3 | 26 | 51 | * | 12 | 4 | 53 | 52 | * | 14 | 5 | 106 | 53 | * | 16 | 6 | 213 | 54 | * 55 | * Use this MATLAB script to visualize the filter: 56 | * 57 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 58 | * NUM_SECTIONS=1; 59 | * a=6; b=1; FS=1; 60 | * DEN = [1 , -2 + 2^-b , 1-2^-b+ 4*2^-a]; 61 | * NUM = 2^(-a)*[1, 2, 1]; 62 | * F=dfilt.df2(NUM,DEN); 63 | * H=F; 64 | * for i=2:NUM_SECTIONS 65 | * H=dfilt.cascade(H,F); 66 | * end 67 | * %H=F^NUM_SECTIONS; 68 | * h=fvtool(H,'Fs',FS) 69 | * zeropos = roots(NUM) 70 | * polepos = roots(DEN) 71 | * set(h,'FrequencyRange', 'Specify freq. vector'); 72 | * set(h,'FrequencyScale','Log') 73 | * set(h,'FrequencyVector', logspace(-4,0,1000)); 74 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 75 | * 76 | */ 77 | class FixedFilter{ 78 | public: 79 | // input and output arrays 80 | temperature_precise xv[3]; 81 | temperature_precise yv[3]; 82 | uint8_t a; //!< Filter `a` coefficient 83 | uint8_t b; //!< Filter `b` coefficient 84 | 85 | public: 86 | FixedFilter() { setCoefficients(20); /* default to a b value of 2 */ } 87 | ~FixedFilter() { } 88 | void init(temperature val); 89 | 90 | /** 91 | * \brief Set filter coefficients 92 | * 93 | * @param bValue - New b value 94 | */ 95 | void setCoefficients(uint8_t bValue) { 96 | a = bValue*2+4; 97 | b = bValue; 98 | } 99 | 100 | temperature add(temperature val); // adds a value and returns the most recent filter output 101 | temperature_precise addDoublePrecision(temperature_precise val); 102 | 103 | temperature readOutput(){ 104 | return yv[0]>>16; // return 16 most significant bits of most recent output 105 | } 106 | 107 | temperature readInput(){ 108 | return xv[0]>>16; // return 16 most significant bits of most recent input 109 | } 110 | 111 | temperature_precise readOutputDoublePrecision(){ 112 | return yv[0]; 113 | } 114 | 115 | temperature_precise readPrevOutputDoublePrecision(){ 116 | return yv[1]; 117 | } 118 | 119 | temperature detectPosPeak(); 120 | temperature detectNegPeak(); 121 | }; 122 | 123 | -------------------------------------------------------------------------------- /src/IicLcd.h: -------------------------------------------------------------------------------- 1 | //YWROBOT 2 | #ifndef LiquidCrystal_I2C_h 3 | #define LiquidCrystal_I2C_h 4 | 5 | #include "Brewpi.h" 6 | #include "BrewpiStrings.h" 7 | #include 8 | #include 9 | #include "Ticks.h" 10 | 11 | // commands 12 | #define LCD_CLEARDISPLAY 0x01 13 | #define LCD_RETURNHOME 0x02 14 | #define LCD_ENTRYMODESET 0x04 15 | #define LCD_DISPLAYCONTROL 0x08 16 | #define LCD_CURSORSHIFT 0x10 17 | #define LCD_FUNCTIONSET 0x20 18 | #define LCD_SETCGRAMADDR 0x40 19 | #define LCD_SETDDRAMADDR 0x80 20 | 21 | // flags for display entry mode 22 | #define LCD_ENTRYRIGHT 0x00 23 | #define LCD_ENTRYLEFT 0x02 24 | #define LCD_ENTRYSHIFTINCREMENT 0x01 25 | #define LCD_ENTRYSHIFTDECREMENT 0x00 26 | 27 | // flags for display on/off control 28 | #define LCD_DISPLAYON 0x04 29 | #define LCD_DISPLAYOFF 0x00 30 | #define LCD_CURSORON 0x02 31 | #define LCD_CURSOROFF 0x00 32 | #define LCD_BLINKON 0x01 33 | #define LCD_BLINKOFF 0x00 34 | 35 | // flags for display/cursor shift 36 | #define LCD_DISPLAYMOVE 0x08 37 | #define LCD_CURSORMOVE 0x00 38 | #define LCD_MOVERIGHT 0x04 39 | #define LCD_MOVELEFT 0x00 40 | 41 | // flags for function set 42 | #define LCD_8BITMODE 0x10 43 | #define LCD_4BITMODE 0x00 44 | #define LCD_2LINE 0x08 45 | #define LCD_1LINE 0x00 46 | #define LCD_5x10DOTS 0x04 47 | #define LCD_5x8DOTS 0x00 48 | 49 | // flags for backlight control 50 | #define LCD_BACKLIGHT 0x08 51 | #define LCD_NOBACKLIGHT 0x00 52 | 53 | #define En B00000100 // Enable bit 54 | #define Rw B00000010 // Read/Write bit 55 | #define Rs B00000001 // Register select bit 56 | 57 | class IIClcd : public Print { 58 | public: 59 | IIClcd(uint8_t lcd_Addr, uint8_t lcd_cols, uint8_t lcd_rows); 60 | ~IIClcd() {}; 61 | 62 | void init(); 63 | 64 | void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS); 65 | 66 | void clear(); 67 | void home(); 68 | 69 | void noDisplay(); 70 | void display(); 71 | void noBlink(); 72 | void blink(); 73 | void noCursor(); 74 | void cursor(); 75 | void scrollDisplayLeft(); 76 | void scrollDisplayRight(); 77 | // void printLeft(); 78 | // void printRight(); 79 | void leftToRight(); 80 | void rightToLeft(); 81 | // void shiftIncrement(); 82 | // void shiftDecrement(); 83 | void noBacklight(); 84 | void backlight(); 85 | void autoscroll(); 86 | void noAutoscroll(); 87 | void scan_address(); 88 | 89 | void createChar(uint8_t, uint8_t[]); 90 | void setCursor(uint8_t, uint8_t); 91 | 92 | virtual size_t write(uint8_t); 93 | 94 | #define print_P_inline 1 95 | #ifdef print_P_inline 96 | // print a string stored in PROGMEM 97 | void print_P(const char * str) { 98 | char buf[21]; // create buffer in RAM 99 | strcpy_P(buf, str); // copy string to RAM 100 | print(buf); // print from RAM 101 | } 102 | #else 103 | void print_P(const char * str); 104 | #endif 105 | 106 | void getLine(uint8_t lineNumber, char * buffer); 107 | 108 | //void readContent(void); // read the content from the display to the shadow copy buffer 109 | char readChar(); 110 | 111 | void command(uint8_t); 112 | 113 | void setBufferOnly(bool bufferOnly) { _bufferOnly = bufferOnly; } 114 | 115 | void resetBacklightTimer(); 116 | 117 | void updateBacklight(); 118 | 119 | uint8_t getCurrPos() { 120 | return _currpos; 121 | } 122 | 123 | uint8_t getCurrLine() { 124 | return _currline; 125 | } 126 | 127 | void printSpacesToRestOfLine(); 128 | 129 | using Print::write; 130 | 131 | private: 132 | void init_priv(); 133 | void send(uint8_t, uint8_t); 134 | void write4bits(uint8_t); 135 | void expanderWrite(uint8_t); 136 | void pulseEnable(uint8_t); 137 | uint8_t _Addr; 138 | uint8_t _displayfunction; 139 | uint8_t _displaycontrol; 140 | uint8_t _displaymode; 141 | uint8_t _numlines; 142 | uint8_t _currline; 143 | uint8_t _currpos; 144 | uint8_t _cols; 145 | uint8_t _rows; 146 | uint8_t _backlightval; 147 | uint16_t _backlightTime; 148 | bool _bufferOnly; 149 | 150 | bool _displayFound; // Needed since writes to a non-existant display can lock I2C bus on ESP32-S2 - see: https://github.com/espressif/arduino-esp32/issues/8480#issuecomment-1708909457 151 | 152 | 153 | char content[4][21]; // always keep a copy of the display content in this variable 154 | }; 155 | 156 | #endif 157 | -------------------------------------------------------------------------------- /src/InkbirdTempSensor.cpp: -------------------------------------------------------------------------------- 1 | #ifdef HAS_BLUETOOTH 2 | #include "Brewpi.h" 3 | #include "InkbirdTempSensor.h" 4 | #include "PiLink.h" // For printBytes 5 | // #include "Ticks.h" 6 | #include "TemperatureFormats.h" 7 | 8 | #include "wireless/BTScanner.h" 9 | 10 | InkbirdTempSensor::~InkbirdTempSensor(){ 11 | // delete sensor; 12 | }; 13 | 14 | /** 15 | * \brief Initializes the temperature sensor. 16 | * 17 | * This method is called when the sensor is first created and also any time the 18 | * sensor reports it's disconnected. If the result is TEMP_SENSOR_DISCONNECTED 19 | * then subsequent calls to read() will also return TEMP_SENSOR_DISCONNECTED. 20 | * Clients should attempt to re-initialize the sensor by calling init() again. 21 | */ 22 | bool InkbirdTempSensor::init() { 23 | if (ib==NULL) { 24 | ib = bt_scanner.get_or_create_inkbird(btAddress); 25 | if (ib==NULL) { 26 | logErrorString(ERROR_SRAM_SENSOR, btAddress.toString().c_str()); 27 | } 28 | } 29 | return isConnected(); 30 | } 31 | 32 | 33 | /** 34 | * \brief Read the value of the sensor 35 | * 36 | * @return TEMP_SENSOR_DISCONNECTED if sensor is not connected, constrained temp otherwise. 37 | * @see readAndConstrainTemp() 38 | */ 39 | temperature InkbirdTempSensor::read(){ 40 | if (!isConnected()) 41 | return TEMP_SENSOR_DISCONNECTED; 42 | 43 | return readAndConstrainTemp(); 44 | } 45 | 46 | 47 | /** 48 | * \brief Reads the temperature. 49 | * 50 | * If successful, constrains the temp to the range of the temperature type 51 | * and updates lastRequestTime. On successful, leaves lastRequestTime alone 52 | * and returns TEMP_SENSOR_DISCONNECTED. 53 | */ 54 | temperature InkbirdTempSensor::readAndConstrainTemp() 55 | { 56 | if(!isConnected()) { 57 | return TEMP_SENSOR_DISCONNECTED; 58 | } 59 | 60 | // double rawTemp = ib->getTemp() / 1000; 61 | // temperature temp = doubleToTemp(rawTemp); 62 | 63 | // const uint8_t shift = TEMP_FIXED_POINT_BITS - sensorPrecision; // difference in precision between DS18B20 format and temperature adt 64 | // temp = constrainTemp(temp+calibrationOffset+(C_OFFSET>>shift), ((int) MIN_TEMP)>>shift, ((int) MAX_TEMP)>>shift)<getTempFixedPoint() + (calibrationOffset<<(TEMP_FIXED_POINT_BITS - TEMP_CALIBRATION_OFFSET_PRECISION)), MIN_TEMP, MAX_TEMP); 67 | return temp; 68 | } 69 | #endif 70 | -------------------------------------------------------------------------------- /src/InkbirdTempSensor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifdef HAS_BLUETOOTH 3 | #include "Brewpi.h" 4 | #include "TempSensor.h" 5 | #include "FastDigitalPin.h" 6 | #include "Ticks.h" 7 | // #include "DallasTemperature.h" // for DeviceAddress 8 | #include 9 | 10 | #include "wireless/Inkbird.h" 11 | 12 | 13 | /** 14 | * \brief An Inkbird bluetooth temperature sensor 15 | * 16 | * \ingroup hardware 17 | */ 18 | class InkbirdTempSensor : public BasicTempSensor { 19 | public: 20 | /** 21 | * \brief Constructs a new Inkbird temp sensor. 22 | * 23 | * /param address The MAC address for this sensor. 24 | * /param calibration A temperature value that is added to all readings. This can be used to calibrate the sensor. 25 | */ 26 | InkbirdTempSensor(NimBLEAddress address, fixed4_4 calibrationOffset) { 27 | btAddress = address; 28 | 29 | this->calibrationOffset = calibrationOffset; 30 | ib = nullptr; 31 | }; 32 | 33 | ~InkbirdTempSensor(); 34 | 35 | /** 36 | * \brief Check if sensor device is connected 37 | */ 38 | bool isConnected(){ 39 | if (ib && ib->isConnected()) 40 | return true; 41 | return false; 42 | } 43 | 44 | bool init(); 45 | temperature read(); 46 | 47 | NimBLEAddress btAddress; 48 | inkbird *ib; 49 | 50 | private: 51 | /** 52 | * \brief The sensor precision, in bits. 53 | */ 54 | // constexpr static uint8_t sensorPrecision = 4; 55 | 56 | temperature readAndConstrainTemp(); 57 | // uint8_t sensorAddress[6]; 58 | 59 | fixed4_4 calibrationOffset; //!< Temperature offset needed for calibration 60 | 61 | }; 62 | #endif -------------------------------------------------------------------------------- /src/JsonKeys.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Matthew McGowan 3 | * Copyright 2013 BrewPi/Elco Jacobs. 4 | * Copyright 2020 Scott Peshak 5 | * 6 | * This file is part of BrewPi. 7 | * 8 | * BrewPi is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * BrewPi is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with BrewPi. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | /** 25 | * \brief Strings used for JSON keys 26 | * \see DeviceDefinition 27 | */ 28 | namespace DeviceDefinitionKeys { 29 | constexpr auto index = "i"; 30 | constexpr auto chamber = "c"; 31 | constexpr auto beer = "b"; 32 | constexpr auto function = "f"; 33 | constexpr auto hardware = "h"; 34 | constexpr auto pin = "p"; 35 | constexpr auto invert = "x"; 36 | constexpr auto deactivated = "d"; 37 | constexpr auto address = "a"; 38 | constexpr auto child_id = "n"; 39 | constexpr auto alias = "r"; // EXTERN_SENSOR_ACTUATOR or Bluetooth 40 | #if BREWPI_DS2413 41 | constexpr auto pio = "n"; 42 | #endif 43 | constexpr auto calibrateadjust = "j"; 44 | 45 | constexpr auto value = "v"; 46 | constexpr auto write = "w"; 47 | 48 | constexpr auto type = "t"; 49 | }; // namespace DeviceDefinitionKeys 50 | 51 | 52 | /** 53 | * \brief Strings used for JSON keys 54 | * \see DeviceDisplay 55 | */ 56 | namespace DeviceDisplayKeys { 57 | constexpr auto index = "i"; 58 | constexpr auto value = "v"; 59 | constexpr auto write = "w"; 60 | constexpr auto empty = "e"; 61 | }; // namespace DeviceDisplayKeys 62 | 63 | 64 | 65 | /** 66 | * \brief Strings used for JSON keys 67 | * \see EnumerateHardware 68 | */ 69 | namespace EnumerateHardwareKeys { 70 | constexpr auto hardware = "h"; 71 | constexpr auto pin = "p"; 72 | constexpr auto values = "v"; 73 | constexpr auto unused = "u"; 74 | constexpr auto function = "f"; 75 | }; // namespace EnumerateHardwareKeys 76 | 77 | 78 | /** 79 | * \brief Strings used for JSON keys 80 | * \see ControlSettings 81 | */ 82 | namespace ControlSettingsKeys { 83 | constexpr auto beer = "beerSetting"; 84 | constexpr auto fridge = "fridgeSetting"; 85 | constexpr auto heatEst = "heatEstimator"; 86 | constexpr auto coolEst = "coolEstimator"; 87 | constexpr auto mode = "mode"; 88 | }; 89 | 90 | 91 | /** 92 | * \brief Strings used for JSON keys 93 | * \see ControlConstants 94 | */ 95 | namespace ControlConstantsKeys { 96 | constexpr auto tempMin = "tempSettingMin"; 97 | constexpr auto tempMax = "tempSettingMax"; 98 | constexpr auto kp = "Kp"; 99 | constexpr auto ki = "Ki"; 100 | constexpr auto kd = "Kd"; 101 | constexpr auto maxError = "iMaxError"; 102 | constexpr auto idleHigh = "idleRangeHigh"; 103 | constexpr auto idleLow = "idleRangeLow"; 104 | constexpr auto heatingUpper = "heatingTargetUpper"; 105 | constexpr auto heatingLower = "heatingTargetLower"; 106 | constexpr auto coolingUpper = "coolingTargetUpper"; 107 | constexpr auto coolingLower = "coolingTargetLower"; 108 | constexpr auto maxHeatEst = "maxHeatTimeForEstimate"; 109 | constexpr auto maxCoolEst = "maxCoolTimeForEstimate"; 110 | constexpr auto fridgeFilterFast = "fridgeFastFilter"; 111 | constexpr auto fridgeFilterSlow = "fridgeSlowFilter"; 112 | constexpr auto fridgeFilterSlope = "fridgeSlopeFilter"; 113 | constexpr auto beerFilterFast = "beerFastFilter"; 114 | constexpr auto beerFilterSlow = "beerSlowFilter"; 115 | constexpr auto beerFilterSlope = "beerSlopeFilter"; 116 | constexpr auto lightHeater = "lightAsHeater"; 117 | constexpr auto rotaryHalfSteps = "rotaryHalfSteps"; 118 | constexpr auto pidMax = "pidMax"; 119 | constexpr auto tempFormat = "tempFormat"; 120 | }; 121 | 122 | 123 | /** 124 | * \brief Strings used for JSON keys 125 | * \see ExtendedSettings 126 | */ 127 | namespace ExtendedSettingsKeys { 128 | constexpr auto eepromReset = "confirmReset"; 129 | constexpr auto invertTFT = "invertTFT"; 130 | constexpr auto glycol = "glycol"; 131 | constexpr auto largeTFT = "largeTFT"; 132 | }; // namespace ExtendedSettingsKeys 133 | 134 | 135 | /** 136 | * \brief Strings used for JSON keys 137 | * \see UpstreamSettings 138 | */ 139 | namespace UpstreamSettingsKeys { 140 | constexpr auto upstreamHost = "upstreamHost"; 141 | constexpr auto upstreamPort = "upstreamPort"; 142 | constexpr auto deviceID = "deviceID"; 143 | }; // namespace UpstreamSettingsKeys 144 | 145 | 146 | 147 | /** 148 | * \brief Strings used for JSON keys 149 | * \see processUpdateModeJson 150 | */ 151 | namespace ModeUpdateKeys { 152 | constexpr auto mode = "mode"; 153 | constexpr auto setpoint = "setPoint"; 154 | }; // namespace ModeUpdateKeys 155 | 156 | 157 | -------------------------------------------------------------------------------- /src/JsonMessages.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "JsonMessages.h" 3 | #include "Brewpi.h" 4 | #include "Version.h" 5 | #include "Display.h" 6 | #include "TempControl.h" 7 | #include "TemperatureFormats.h" 8 | 9 | 10 | 11 | 12 | void versionInfoJson(DynamicJsonDocument &doc) { 13 | // v version 14 | // s shield type 15 | // y: simulator 16 | // b: board 17 | // e: 18 | 19 | doc["v"] = Config::Version::release; 20 | doc["n"] = Config::Version::git_rev; 21 | doc["c"] = Config::Version::git_tag; 22 | doc["s"] = BREWPI_STATIC_CONFIG; 23 | doc["y"] = BREWPI_SIMULATE; 24 | doc["b"] = String(BREWPI_BOARD); 25 | doc["l"] = BREWPI_LOG_MESSAGES_VERSION; 26 | doc["e"] = FIRMWARE_REVISION; 27 | 28 | } 29 | 30 | 31 | void getLcdContentJson(DynamicJsonDocument &doc) { 32 | JsonArray rootArray = doc.to(); 33 | char stringBuffer[Config::Lcd::columns + 2]; 34 | 35 | for (uint8_t i = 0; i < Config::Lcd::lines; i++) { 36 | display.getLine(i, stringBuffer); 37 | rootArray.add(stringBuffer); 38 | } 39 | } 40 | 41 | void printTemperaturesJson(DynamicJsonDocument &doc, const char *beerAnnotation, const char *fridgeAnnotation) { 42 | 43 | doc["BeerTemp"] = tempToDouble(tempControl.getBeerTemp(), Config::TempFormat::tempDecimals); 44 | doc["BeerSet"] = tempToDouble(tempControl.getBeerSetting(), Config::TempFormat::tempDecimals); 45 | 46 | doc["BeerAnn"] = beerAnnotation; 47 | 48 | doc["FridgeTemp"] = tempToDouble(tempControl.getFridgeTemp(), Config::TempFormat::tempDecimals); 49 | doc["FridgeSet"] = tempToDouble(tempControl.getFridgeSetting(), Config::TempFormat::tempDecimals); 50 | 51 | doc["FridgeAnn"] = fridgeAnnotation; 52 | 53 | if (tempControl.ambientSensor->isConnected()) { 54 | doc["RoomTemp"] = tempToDouble(tempControl.getRoomTemp(), Config::TempFormat::tempDecimals); 55 | } else { 56 | doc["RoomTemp"] = ""; 57 | } 58 | 59 | doc["State"] = tempControl.getState(); 60 | 61 | #if BREWPI_SIMULATE 62 | doc["Time"] = ticks.millis() / 1000; 63 | #endif 64 | } 65 | 66 | void printTemperaturesJson(DynamicJsonDocument &doc) { 67 | printTemperaturesJson(doc, "", ""); 68 | } 69 | 70 | void getFullTemperatureControlJson(DynamicJsonDocument &doc) { 71 | DynamicJsonDocument cc(256); 72 | DynamicJsonDocument cs(256); 73 | DynamicJsonDocument cv(256); 74 | DynamicJsonDocument temp(1024); 75 | 76 | tempControl.getControlConstantsDoc(cc); 77 | tempControl.getControlSettingsDoc(cs); 78 | tempControl.getControlVariablesDoc(cv); 79 | printTemperaturesJson(temp); 80 | 81 | // For this message, we don't want to send any temperature if the sensor is not connected 82 | if(!tempControl.beerSensor->isConnected()) 83 | temp["BeerTemp"] = ""; 84 | if(!tempControl.fridgeSensor->isConnected()) 85 | temp["FridgeTemp"] = ""; 86 | 87 | doc["cc"] = cc; 88 | doc["cs"] = cs; 89 | doc["cv"] = cv; 90 | doc["temp"] = temp; 91 | } 92 | -------------------------------------------------------------------------------- /src/JsonMessages.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | 5 | void versionInfoJson(DynamicJsonDocument &doc); 6 | void getLcdContentJson(DynamicJsonDocument &doc); 7 | void printTemperaturesJson(DynamicJsonDocument &doc, const char *beerAnnotation, const char *fridgeAnnotation); 8 | void printTemperaturesJson(DynamicJsonDocument &doc); 9 | void getFullTemperatureControlJson(DynamicJsonDocument &doc); 10 | 11 | -------------------------------------------------------------------------------- /src/Logger.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * 4 | * This file is part of BrewPi. 5 | * 6 | * BrewPi is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BrewPi is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BrewPi. If not, see . 18 | */ 19 | 20 | #include "Brewpi.h" 21 | #include "BrewpiStrings.h" 22 | #include "Logger.h" 23 | #include "PiLink.h" 24 | #include "TemperatureFormats.h" 25 | 26 | 27 | /** 28 | * \brief Log a message 29 | * 30 | * \param type - Type of message 31 | * \param errorID 32 | */ 33 | void Logger::logMessageVaArg(const char type, const LOG_ID_TYPE errorID, const char * varTypes, ...){ 34 | DynamicJsonDocument doc(2048); 35 | 36 | va_list args; 37 | doc[F("logType")] = String(type); 38 | doc[F("logID")] = errorID; 39 | JsonArray varArray = doc.createNestedArray("V"); 40 | 41 | va_start (args, varTypes); 42 | uint8_t index = 0; 43 | char buf[9]; 44 | while(varTypes[index]){ 45 | switch(varTypes[index]){ 46 | case 'd': // integer, signed or unsigned 47 | varArray.add(va_arg(args, int)); 48 | break; 49 | case 's': // string 50 | varArray.add(String(va_arg(args, char*))); 51 | break; 52 | case 't': // temperature in fixed_7_9 format 53 | varArray.add(String(tempToString(buf, va_arg(args,int), 1, 12))); 54 | break; 55 | case 'f': // fixed point value 56 | varArray.add(String(fixedPointToString(buf, (temperature) va_arg(args,int), 3, 12))); 57 | break; 58 | } 59 | 60 | index++; 61 | } 62 | va_end (args); 63 | piLink.sendJsonMessage('D', doc); 64 | } 65 | 66 | Logger logger; 67 | -------------------------------------------------------------------------------- /src/Logger.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * 4 | * This file is part of BrewPi. 5 | * 6 | * BrewPi is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BrewPi is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BrewPi. If not, see . 18 | */ 19 | 20 | #ifndef BREWPI_LOGGER_H 21 | #define BREWPI_LOGGER_H 22 | 23 | #include 24 | #include "TemperatureFormats.h" 25 | #include "LogMessages.h" 26 | 27 | // define error id variable type to make it easy to bump to uint16 when needed 28 | #define LOG_ID_TYPE uint8_t 29 | 30 | class Logger{ 31 | public: 32 | Logger(){}; 33 | ~Logger(){}; 34 | 35 | static void logMessageVaArg(const char type, const LOG_ID_TYPE errorID, const char * varTypes, ...); 36 | }; 37 | extern Logger logger; 38 | 39 | 40 | #if BREWPI_LOG_ERRORS 41 | inline void logError(uint8_t debugId){ 42 | logger.logMessageVaArg('E', debugId, ""); 43 | } 44 | inline void logErrorInt(uint8_t debugId, int val){ 45 | logger.logMessageVaArg('E', debugId, "d", val); 46 | } 47 | inline void logErrorString(uint8_t debugId, const char * val){ 48 | logger.logMessageVaArg('E', debugId, "s", val); 49 | } 50 | inline void logErrorTemp(uint8_t debugId, temperature temp){ 51 | logger.logMessageVaArg('E', debugId, "t", temp); 52 | } 53 | inline void logErrorIntInt(uint8_t debugId, int val1, int val2){ 54 | logger.logMessageVaArg('E', debugId, "dd", val1, val2); 55 | } 56 | inline void logErrorIntIntInt(uint8_t debugId, int val1, int val2, int val3){ 57 | logger.logMessageVaArg('E', debugId, "ddd", val1, val2, val3); 58 | } 59 | #else 60 | #define logError(debugId) {} 61 | #define logErrorInt(debugId, val) {} 62 | #define logErrorString(debugId, val) {} 63 | #define logErrorTemp(debugId, temp) {} 64 | #define logErrorIntInt(debugId, val1, val2) {} 65 | #define logErrorIntIntInt(debugId, val1, val2, val3) {} 66 | #endif 67 | 68 | #if BREWPI_LOG_WARNINGS 69 | inline void logWarning(uint8_t debugId){ 70 | logger.logMessageVaArg('W', debugId, ""); 71 | } 72 | inline void logWarningInt(uint8_t debugId, int val){ 73 | logger.logMessageVaArg('W', debugId, "d", val); 74 | } 75 | inline void logWarningString(uint8_t debugId, const char * val){ 76 | logger.logMessageVaArg('W', debugId, "s", val); 77 | } 78 | inline void logWarningTemp(uint8_t debugId, temperature temp){ 79 | logger.logMessageVaArg('W', debugId, "t", temp); 80 | } 81 | inline void logWarningIntString(uint8_t debugId, int val1, const char *val2){ 82 | logger.logMessageVaArg('W', debugId, "ds", val1, val2); 83 | } 84 | #else 85 | #define logWarning(debugId) {} 86 | #define logWarningInt(debugId, val) {} 87 | #define logWarningString(debugId, val) {} 88 | #define logWarningTemp(debugId, temp) {} 89 | #define logWarningIntString(debugId, val1, val2) {} 90 | #endif 91 | 92 | #if BREWPI_LOG_INFO 93 | inline void logInfo(uint8_t debugId){ 94 | logger.logMessageVaArg('I', debugId, ""); 95 | } 96 | inline void logInfoInt(uint8_t debugId, int val){ 97 | logger.logMessageVaArg('I', debugId, "d", val); 98 | } 99 | inline void logInfoString(uint8_t debugId, const char * val){ 100 | logger.logMessageVaArg('I', debugId, "s", val); 101 | } 102 | inline void logInfoTemp(uint8_t debugId, temperature temp){ 103 | logger.logMessageVaArg('I', debugId, "t", temp); 104 | } 105 | inline void logInfoIntString(uint8_t debugId, int val1, const char * val2){ 106 | logger.logMessageVaArg('I', debugId, "ds", val1, val2); 107 | } 108 | inline void logInfoStringString(uint8_t debugId, const char * val1, const char * val2){ 109 | logger.logMessageVaArg('I', debugId, "ss", val1, val2); 110 | } 111 | inline void logInfoIntStringTemp(uint8_t debugId, int val1, const char * val2, temperature val3){ 112 | logger.logMessageVaArg('I', debugId, "dst", val1, val2, val3); 113 | } 114 | inline void logInfoTempTempFixedFixed(uint8_t debugId, temperature t1, temperature t2, temperature f1, temperature f2){ 115 | logger.logMessageVaArg('I', debugId, "ttff", t1, t2, f1, f2); 116 | } 117 | #else 118 | #define logInfo(debugId) {} 119 | #define logInfoInt(debugId, val) {} 120 | #define logInfoString(debugId, val) {} 121 | #define logInfoTemp(debugId, temp) {} 122 | #define logInfoStringString(debugId, val1, val2) {} 123 | #define logInfoIntString(debugId, val1, val2) {} 124 | #define logInfoIntStringTemp(debugId, val1, val2, val3) {} 125 | 126 | 127 | #endif 128 | 129 | #if BREWPI_LOG_DEBUG 130 | #include "PiLink.h" 131 | #define logDebug(string, ...) piLink.debugMessage(PSTR(string), ##__VA_ARGS__) 132 | #else 133 | #define logDebug(string, ...) {} 134 | #endif 135 | 136 | #endif 137 | -------------------------------------------------------------------------------- /src/Menu.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * 4 | * This file is part of BrewPi. 5 | * 6 | * BrewPi is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BrewPi is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BrewPi. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "Brewpi.h" 23 | 24 | #ifndef BREWPI_MENU 25 | #define BREWPI_MENU 1 26 | #endif 27 | 28 | 29 | #if BREWPI_MENU 30 | 31 | #include 32 | #include "TemperatureFormats.h" 33 | 34 | enum menuPages{ 35 | MENU_TOP, 36 | MENU_PROFILE_SETTING, 37 | MENU_BEER_SETTING, 38 | MENU_FRIDGE_SETTING, 39 | MENU_PROFILE 40 | }; 41 | 42 | class Menu{ 43 | public: 44 | Menu(){}; 45 | static void pickSettingToChange(); 46 | static void pickMode(); 47 | static void pickBeerSetting(); 48 | static void pickFridgeSetting(); 49 | static void initRotaryWithTemp(temperature oldSetting); 50 | 51 | ~Menu(){}; 52 | private: 53 | static void pickSettingToChangeLoop(); 54 | }; 55 | 56 | extern Menu menu; 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/NullLcdDriver.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * 4 | * This file is part of BrewPi. 5 | * 6 | * BrewPi is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BrewPi is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BrewPi. If not, see . 18 | */ 19 | 20 | #include "Brewpi.h" 21 | #include 22 | #include 23 | #include 24 | 25 | #include "NullLcdDriver.h" 26 | 27 | 28 | void NullLcdDriver::init() 29 | { 30 | } 31 | 32 | void NullLcdDriver::begin(uint8_t cols, uint8_t lines) { 33 | _numlines = lines; 34 | _currline = 0; 35 | _currpos = 0; 36 | 37 | clear(); 38 | home(); 39 | display(); 40 | } 41 | 42 | /********** high level commands, for the user! */ 43 | void NullLcdDriver::clear() 44 | { 45 | for(uint8_t i = 0; i<4; i++){ 46 | for(uint8_t j = 0; j<20; j++){ 47 | content[i][j]=' '; // initialize on all spaces 48 | } 49 | content[i][20]='\0'; // NULL terminate string 50 | } 51 | } 52 | 53 | void NullLcdDriver::home() 54 | { 55 | _currline = 0; 56 | _currpos = 0; 57 | } 58 | 59 | void NullLcdDriver::setCursor(uint8_t col, uint8_t row) 60 | { 61 | if ( row >= _numlines ) { 62 | row = 0; //write to first line if out off bounds 63 | } 64 | _currline = row; 65 | _currpos = col; 66 | } 67 | 68 | // Turn the display on/off (quickly) 69 | void NullLcdDriver::noDisplay() { 70 | } 71 | void NullLcdDriver::display() { 72 | } 73 | 74 | // Turns the underline cursor on/off 75 | void NullLcdDriver::noCursor() { 76 | } 77 | void NullLcdDriver::cursor() { 78 | } 79 | 80 | // Turn on and off the blinking cursor 81 | void NullLcdDriver::noBlink() { 82 | } 83 | void NullLcdDriver::blink() { 84 | } 85 | 86 | // These commands scroll the display without changing the RAM 87 | void NullLcdDriver::scrollDisplayLeft() { 88 | } 89 | void NullLcdDriver::scrollDisplayRight() { 90 | } 91 | 92 | // This is for text that flows Left to Right 93 | void NullLcdDriver::leftToRight() { 94 | } 95 | 96 | // This is for text that flows Right to Left 97 | void NullLcdDriver::rightToLeft() { 98 | } 99 | 100 | // This will 'right justify' text from the cursor 101 | void NullLcdDriver::autoscroll() { 102 | } 103 | 104 | // This will 'left justify' text from the cursor 105 | void NullLcdDriver::noAutoscroll() { 106 | } 107 | 108 | // Allows us to fill the first 8 CGRAM locations 109 | // with custom characters 110 | void NullLcdDriver::createChar(uint8_t location, uint8_t charmap[]) { 111 | location &= 0x7; // we only have 8 locations 0-7 112 | for (int i=0; i<8; i++) { 113 | write(charmap[i]); 114 | } 115 | } 116 | 117 | // This resets the backlight timer and updates the SPI output 118 | void NullLcdDriver::resetBacklightTimer(){ 119 | } 120 | 121 | void NullLcdDriver::updateBacklight(){ 122 | } 123 | 124 | // Puts the content of one LCD line into the provided buffer. 125 | void NullLcdDriver::getLine(uint8_t lineNumber, char * buffer){ 126 | const char* src = content[lineNumber]; 127 | for(uint8_t i =0;i<20;i++){ 128 | char c = src[i]; 129 | buffer[i] = (c == 0b11011111) ? 0xB0 : c; 130 | } 131 | buffer[20] = '\0'; // NULL terminate string 132 | } 133 | 134 | /*********** mid level commands, for sending data/cmds */ 135 | 136 | inline void NullLcdDriver::command(uint8_t value) { 137 | } 138 | 139 | inline size_t NullLcdDriver::write(uint8_t value) { 140 | content[_currline][_currpos] = value; 141 | _currpos++; 142 | return 1; 143 | } 144 | 145 | void NullLcdDriver::printSpacesToRestOfLine(){ 146 | while(_currpos < 20){ 147 | print(' ') ; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/NullLcdDriver.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2013 BrewPi/Elco Jacobs. 4 | * Copyright 2013 Matthew McGowan. 5 | * 6 | * This file is part of BrewPi. 7 | * 8 | * BrewPi is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * BrewPi is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with BrewPi. If not, see . 20 | */ 21 | 22 | #pragma once 23 | 24 | #include "Brewpi.h" 25 | #include "BrewpiStrings.h" 26 | #include 27 | #include 28 | #include "Ticks.h" 29 | 30 | class NullLcdDriver : public Print { 31 | public: 32 | // Constants are set in initializer list of constructor 33 | NullLcdDriver(){}; 34 | ~NullLcdDriver(){}; 35 | 36 | void init(); 37 | 38 | void begin(uint8_t cols, uint8_t rows); 39 | 40 | void clear(); 41 | void home(); 42 | 43 | void noDisplay(); 44 | void display(); 45 | void noBlink(); 46 | void blink(); 47 | void noCursor(); 48 | void cursor(); 49 | void scrollDisplayLeft(); 50 | void scrollDisplayRight(); 51 | void leftToRight(); 52 | void rightToLeft(); 53 | void autoscroll(); 54 | void noAutoscroll(); 55 | 56 | void createChar(uint8_t, uint8_t[]); 57 | void setCursor(uint8_t, uint8_t); 58 | 59 | virtual size_t write(uint8_t); 60 | 61 | void print_P(const char * str){ // print a string stored in PROGMEM 62 | char buf[21]; // create buffer in RAM 63 | strcpy_P(buf, str); // copy string to RAM 64 | print(buf); // print from RAM 65 | } 66 | 67 | // copy a line from the shadow copy to a string buffer and correct the degree sign 68 | void getLine(uint8_t lineNumber, char * buffer); 69 | 70 | void readContent(); // read the content from the display to the shadow copy buffer 71 | 72 | void command(uint8_t); 73 | char readChar(); 74 | 75 | void setBufferOnly(bool bufferOnly) { _bufferOnly = bufferOnly; } 76 | 77 | void resetBacklightTimer(); 78 | 79 | void updateBacklight(); 80 | 81 | uint8_t getCurrPos(){ 82 | return _currpos; 83 | } 84 | uint8_t getCurrLine(){ 85 | return _currline; 86 | } 87 | 88 | // Write spaces from current position to line end. 89 | void printSpacesToRestOfLine(); 90 | 91 | using Print::write; 92 | 93 | private: 94 | uint8_t _currline; 95 | uint8_t _currpos; 96 | uint8_t _numlines; 97 | 98 | bool _bufferOnly; 99 | 100 | char content[4][21]; // always keep a copy of the display content in this variable 101 | 102 | }; 103 | 104 | -------------------------------------------------------------------------------- /src/NumberFormats.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #include "NumberFormats.h" 22 | 23 | /** 24 | * \brief Parse string into 8-bit bytes 25 | */ 26 | void parseBytes(uint8_t *data, const char *s, uint8_t len) { 27 | char c; 28 | while ((c = *s++)) { 29 | uint8_t d = (c >= 'A' ? c - 'A' + 10 : c - '0') << 4; 30 | c = *s++; 31 | d |= (c >= 'A' ? c - 'A' + 10 : c - '0'); 32 | *data++ = d; 33 | } 34 | } 35 | 36 | /** 37 | * \brief Render 8-bit data as hex 38 | */ 39 | void printBytes(const uint8_t *data, uint8_t len, char *buf) { 40 | for (int i = 0; i < len; i++) { 41 | uint8_t b = (data[i] >> 4) & 0x0f; 42 | *buf++ = (b > 9 ? b - 10 + 'A' : b + '0'); 43 | b = data[i] & 0x0f; 44 | *buf++ = (b > 9 ? b - 10 + 'A' : b + '0'); 45 | } 46 | *buf = 0; 47 | } 48 | -------------------------------------------------------------------------------- /src/NumberFormats.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | #pragma once 21 | 22 | #include 23 | 24 | void parseBytes(uint8_t *data, const char *s, uint8_t len); 25 | void printBytes(const uint8_t *data, uint8_t len, char *buf); 26 | -------------------------------------------------------------------------------- /src/OLEDFourBit.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 BrewPi/Elco Jacobs. 3 | * 4 | * This file is part of BrewPi. 5 | * 6 | * BrewPi is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BrewPi is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BrewPi. If not, see . 18 | */ 19 | 20 | /* This is an adaptation of the Arduino LiquidCrystal library for the 21 | * NHD-0420DZW-AY5-ND OLED display, made by NewHaven. The display should be HD44780 compatible but isn't. 22 | * Differences are some of the control commands (cursor on/off), language setting and especially initialization sequence. 23 | */ 24 | 25 | #ifndef OLEDFourBit_h 26 | #define OLEDFourBit_h 27 | 28 | #include 29 | #include "Print.h" 30 | #include "Pins.h" 31 | 32 | // commands 33 | #define LCD_CLEARDISPLAY 0x01 34 | #define LCD_RETURNHOME 0x02 35 | #define LCD_ENTRYMODESET 0x04 36 | #define LCD_DISPLAYCONTROL 0x08 37 | #define LCD_CURSORSHIFT 0x10 38 | #define LCD_FUNCTIONSET 0x28 39 | #define LCD_SETCGRAMADDR 0x40 40 | #define LCD_SETDDRAMADDR 0x80 41 | 42 | // flags for display entry mode 43 | #define LCD_ENTRYRIGHT 0x00 44 | #define LCD_ENTRYLEFT 0x02 45 | #define LCD_ENTRYSHIFTINCREMENT 0x01 46 | #define LCD_ENTRYSHIFTDECREMENT 0x00 47 | 48 | // flags for display on/off control 49 | #define LCD_DISPLAYON 0x04 50 | #define LCD_DISPLAYOFF 0x00 51 | #define LCD_CURSORON 0x02 52 | #define LCD_CURSOROFF 0x00 53 | #define LCD_BLINKON 0x01 54 | #define LCD_BLINKOFF 0x00 55 | 56 | // flags for display/cursor shift 57 | #define LCD_DISPLAYMOVE 0x08 58 | #define LCD_CURSORMOVE 0x00 59 | #define LCD_MOVERIGHT 0x04 60 | #define LCD_MOVELEFT 0x00 61 | 62 | // flags for function set 63 | #define LCD_8BITMODE 0x10 64 | #define LCD_4BITMODE 0x00 65 | #define LCD_ENGLISH_JAPANESE 0x00 66 | #define LCD_WESTERN_EUROPEAN_1 0x01 67 | #define LCD_ENGLISH_RUSSIAN 0x02 68 | #define LCD_WESTERN_EUROPEAN_2 0x03 69 | 70 | class OLEDFourBit : public Print { 71 | public: 72 | OLEDFourBit(){}; 73 | 74 | #if BREWPI_STATIC_CONFIG==BREWPI_SHIELD_DIY 75 | void init() { 76 | init(DISP_RS, DISP_RW, DISP_EN, DISP_D4, DISP_D5, DISP_D6, DISP_D7); // initialize OLED with these pins 77 | } 78 | #endif 79 | 80 | void init(uint8_t rs, uint8_t rw, uint8_t enable, 81 | uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7); 82 | 83 | void begin(uint8_t cols, uint8_t rows); 84 | 85 | void clear(); 86 | void home(); 87 | 88 | void noDisplay(); 89 | void display(); 90 | void noBlink(); 91 | void blink(); 92 | void noCursor(); 93 | void cursor(); 94 | void scrollDisplayLeft(); 95 | void scrollDisplayRight(); 96 | void leftToRight(); 97 | void rightToLeft(); 98 | void autoscroll(); 99 | void noAutoscroll(); 100 | 101 | void createChar(uint8_t, uint8_t[]); 102 | void setCursor(uint8_t, uint8_t); 103 | 104 | virtual size_t write(uint8_t); 105 | 106 | size_t print_P(const char * str) { // print a string stored in PROGMEM 107 | char buf[21]; // create buffer in RAM 108 | strlcpy(buf, str, 20); // ESP8266 has no concept of PROGMEM - we're good 109 | return print(buf); // print from RAM 110 | } 111 | 112 | // copy a line from the shadow copy to a string buffer and correct the degree sign 113 | void getLine(uint8_t lineNumber, char * buffer); 114 | 115 | void readContent(); // read the content from the display to the shadow copy buffer 116 | 117 | void command(uint8_t); 118 | char readChar(); 119 | 120 | void setBufferOnly(bool bufferOnly) {} 121 | 122 | void printSpacesToRestOfLine(); 123 | 124 | void resetBacklightTimer(){ /* not implemented for OLED, doesn't have a backlight. */ } 125 | 126 | void updateBacklight(){ /* not implemented for OLED, doesn't have a backlight. */ } 127 | 128 | using Print::write; 129 | 130 | private: 131 | void send(uint8_t, uint8_t); 132 | void write4bits(uint8_t); 133 | void pulseEnable(); 134 | void waitBusy(); 135 | 136 | uint8_t _rs_pin; // LOW: command. HIGH: character. 137 | uint8_t _rw_pin; // LOW: write to oled. HIGH: read from oled. 138 | uint8_t _enable_pin; // activated by a HIGH pulse. 139 | uint8_t _busy_pin; 140 | uint8_t _data_pins[4]; 141 | 142 | uint8_t _displayfunction; 143 | uint8_t _displaycontrol; 144 | uint8_t _displaymode; 145 | uint8_t _initialized; 146 | uint8_t _currline; 147 | uint8_t _currpos; 148 | uint8_t _numlines; 149 | 150 | char content[4][21]; // always keep a copy of the display content in this variable 151 | 152 | bool _bufferOnly; 153 | 154 | }; 155 | 156 | #endif 157 | -------------------------------------------------------------------------------- /src/OneWireActuator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #ifdef ARDUINO 24 | 25 | #include "Brewpi.h" 26 | #include "Actuator.h" 27 | 28 | #ifdef BREWPI_DS2413 29 | #include "DS2413.h" 30 | #endif 31 | 32 | #include "PiLink.h" 33 | 34 | /** 35 | * An actuator or sensor that operates by communicating with a DS2413 device. 36 | * 37 | */ 38 | class OneWireActuator : public Actuator 39 | #if DS2413_SUPPORT_SENSE 40 | , SwitchSensor 41 | #endif 42 | { 43 | public: 44 | 45 | OneWireActuator(OneWire* bus, DeviceAddress address, pio_t pio, bool invert=true) { 46 | init(bus, address, pio, invert); 47 | } 48 | 49 | void init(OneWire* bus, DeviceAddress address, pio_t pio, bool invert=true) { 50 | this->invert = invert; 51 | this->pio = pio; 52 | device.init(bus, address); 53 | } 54 | 55 | void setActive(bool active) { 56 | device.channelWrite(pio, active^invert); 57 | } 58 | 59 | bool isActive() { 60 | return device.channelRead(pio, false); 61 | } 62 | 63 | #if DS2413_SUPPORT_SENSE 64 | bool sense() { 65 | device.channelWrite(pio, 0); 66 | return device.channelSense(pio, invert); // on device failure, default is high for invert, low for regular. 67 | } 68 | #endif 69 | 70 | private: 71 | #ifdef BREWPI_DS2413 72 | DS2413 device; 73 | #endif 74 | pio_t pio; 75 | bool invert; 76 | }; 77 | 78 | #endif -------------------------------------------------------------------------------- /src/OneWireDevices.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #include "Brewpi.h" 22 | 23 | void parseBytes(uint8_t* data, const char* s, uint8_t len); 24 | void printBytes(const uint8_t* data, uint8_t len, char* buf); 25 | -------------------------------------------------------------------------------- /src/OneWireTempSensor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "Brewpi.h" 24 | #include "TempSensor.h" 25 | #include "FastDigitalPin.h" 26 | #include "Ticks.h" 27 | 28 | class DallasTemperature; 29 | class OneWire; 30 | typedef uint8_t DeviceAddress[8]; 31 | 32 | /** 33 | * \brief A OneWire attached temperature sensor 34 | * 35 | * \ingroup hardware 36 | */ 37 | class OneWireTempSensor : public BasicTempSensor { 38 | public: 39 | /** 40 | * \brief Constructs a new onewire temp sensor. 41 | * 42 | * /param bus The onewire bus this sensor is on. 43 | * /param address The onewire address for this sensor. If all bytes are 0 in the address, the first temp sensor 44 | * on the bus is used. 45 | * /param calibration A temperature value that is added to all readings. This can be used to calibrate the sensor. 46 | */ 47 | OneWireTempSensor(OneWire* bus, DeviceAddress address, fixed4_4 calibrationOffset) 48 | : oneWire(bus), sensor(NULL) { 49 | connected = true; // assume connected. Transition from connected to disconnected prints a message. 50 | memcpy(sensorAddress, address, sizeof(DeviceAddress)); 51 | this->calibrationOffset = calibrationOffset; 52 | }; 53 | 54 | ~OneWireTempSensor(); 55 | 56 | /** 57 | * \brief Check if sensor device is connected 58 | */ 59 | bool isConnected(){ 60 | return connected; 61 | } 62 | 63 | bool init(); 64 | temperature read(); 65 | 66 | private: 67 | /** 68 | * \brief The sensor precision, in bits. 69 | */ 70 | constexpr static uint8_t sensorPrecision = 4; 71 | 72 | void setConnected(bool connected); 73 | bool requestConversion(); 74 | 75 | 76 | /** 77 | * \brief Wait for sensor to sample the environment 78 | */ 79 | void waitForConversion() 80 | { 81 | wait.millis(750); 82 | } 83 | 84 | temperature readAndConstrainTemp(); 85 | 86 | OneWire * oneWire; 87 | DallasTemperature * sensor; 88 | DeviceAddress sensorAddress; //!< Sensor address 89 | 90 | fixed4_4 calibrationOffset; //!< Temperature offset needed for calibration 91 | bool connected; //!< Probe connection state 92 | 93 | }; 94 | -------------------------------------------------------------------------------- /src/PiLink.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * Copyright 2020 Scott Peshak 5 | * 6 | * This file is part of BrewPi. 7 | * 8 | * BrewPi is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * BrewPi is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with BrewPi. If not, see . 20 | */ 21 | 22 | #pragma once 23 | #include 24 | #include 25 | 26 | #include "Brewpi.h" 27 | #include "DeviceManager.h" 28 | #include "DeviceNameManager.h" 29 | #include "Logger.h" 30 | #include "PiStream.h" 31 | #include 32 | #include "JsonMessages.h" 33 | 34 | class DeviceConfig; 35 | 36 | /** 37 | * \brief Interface between brewpi controller and the outside world (Commonly a 38 | * RaspberryPi, hence the name). 39 | */ 40 | template class PiLink : public PiStream { 41 | static_assert(std::is_base_of::value, "StreamType must be a Stream"); 42 | 43 | public: 44 | PiLink(StreamType &stream) : PiStream(stream) {} 45 | 46 | /** 47 | * \brief Notify the Pi of the current state. 48 | * 49 | * Forcibly sends the current temperature information to cause data logging. 50 | * Optionally includes an annotation. 51 | * 52 | * \param beerAnnotation - Annotation for the beer 53 | * \param fridgeAnnotation - Annotation for the beer 54 | */ 55 | void sendStateNotification(const char *beerAnnotation = nullptr, const char *fridgeAnnotation = nullptr) { 56 | printTemperatures(beerAnnotation, fridgeAnnotation); 57 | } 58 | 59 | /** 60 | * \brief Send a status message containing the current temperatures 61 | * 62 | * Can include optional annotations. The monitoring script will process 63 | * and log this data. While this is also the response to the request for 64 | * temperature ('t') command, it is used as a general purpose alert to the 65 | * controller script. (This is why it is included in PiLink, and not 66 | * CommandProcessor, despite the latter seeming to be a more logical 67 | * location 68 | * \param beerAnnotation - Annotation for the beer 69 | * \param fridgeAnnotation - Annotation for the beer 70 | */ 71 | void printTemperatures(const char *beerAnnotation, const char *fridgeAnnotation) { 72 | // StaticJsonDocument<1024> doc; 73 | DynamicJsonDocument doc(1024); 74 | printTemperaturesJson(doc, beerAnnotation, fridgeAnnotation); 75 | this->sendJsonMessage('T', doc); 76 | } 77 | }; 78 | 79 | #if defined(ESP32S2) 80 | extern PiLink::type> piLink; 81 | #else 82 | extern PiLink::type> piLink; 83 | #endif 84 | -------------------------------------------------------------------------------- /src/Pins.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * 4 | * This file is part of BrewPi. 5 | * 6 | * BrewPi is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BrewPi is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BrewPi. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "Brewpi.h" 23 | 24 | #if BREWPI_STATIC_CONFIG==BREWPI_SHIELD_REV_A 25 | #ifndef beerSensorPin 26 | #define beerSensorPin A5 // OneWire 1 27 | #endif 28 | 29 | #ifndef fridgeSensorPin 30 | #define fridgeSensorPin A4 // OneWire 2 31 | #endif 32 | 33 | #ifndef coolingPin 34 | #define coolingPin 6 35 | #endif 36 | 37 | #ifndef heatingPin 38 | #define heatingPin 5 39 | #endif 40 | 41 | #endif 42 | 43 | #if BREWPI_STATIC_CONFIG==BREWPI_SHIELD_REV_C 44 | 45 | #ifndef oneWirePin 46 | #define oneWirePin A4 47 | #endif 48 | 49 | #ifndef actuatorPin1 50 | #define actuatorPin1 2 51 | #endif 52 | 53 | #ifndef actuatorPin2 54 | #define actuatorPin2 5 55 | #endif 56 | 57 | #ifndef actuatorPin3 58 | #define actuatorPin3 6 59 | #endif 60 | 61 | #ifndef actuatorPin4 62 | #define actuatorPin4 A5 63 | #endif 64 | 65 | #endif 66 | 67 | #if BREWPI_STATIC_CONFIG==BREWPI_SHIELD_REV_A || BREWPI_STATIC_CONFIG==BREWPI_SHIELD_REV_C 68 | 69 | #ifndef doorPin 70 | #define doorPin 4 71 | #endif 72 | 73 | #ifndef alarmPin 74 | #define alarmPin 3 75 | #endif 76 | 77 | #ifndef lcdLatchPin 78 | #define lcdLatchPin 10 79 | #endif 80 | 81 | // If you change the interrupt pins, you will also have to review the interrupt vectors of the rotary encoder 82 | #define rotarySwitchPin 7 // INT6 on leo or PCINT23 on uno 83 | #define rotaryAPin 8 // PCINT4 on leo or PCINT0 on uno 84 | #define rotaryBPin 9 // PCINT5 on leo or PCINT1 on uno 85 | 86 | #define BREWPI_INVERT_ACTUATORS 1 87 | 88 | #elif BREWPI_STATIC_CONFIG==BREWPI_SHIELD_DIY 89 | 90 | // pins 91 | #ifndef oneWirePin // So we can specify a single bus if we prefer 92 | #ifndef beerSensorPin 93 | #define beerSensorPin 10 94 | #endif 95 | 96 | #ifndef fridgeSensorPin 97 | #define fridgeSensorPin 11 98 | #endif 99 | #endif 100 | // Pay attention when changing the pins for the rotary encoder. 101 | // They should be connected to external interrupt INT0, INT1 and INT3 102 | 103 | #ifndef rotaryAPin 104 | #define rotaryAPin 2 // INT1 105 | #endif 106 | 107 | #ifndef rotaryBPin 108 | #define rotaryBPin 1 // INT3 109 | #endif 110 | 111 | #ifndef rotarySwitchPin 112 | #define rotarySwitchPin 0 // INT2 113 | #endif 114 | 115 | #ifndef coolingPin 116 | #define coolingPin 12 117 | #endif 118 | 119 | #ifndef heatingPin 120 | #define heatingPin 13 121 | #endif 122 | 123 | #ifndef doorPin 124 | #define doorPin A5 125 | #endif 126 | 127 | // TODO - Fix the code for the LCD module 128 | #define DISP_RS 9 129 | #define DISP_RW 8 130 | #define DISP_EN 7 131 | #define DISP_D4 6 132 | #define DISP_D5 5 133 | #define DISP_D6 4 134 | #define DISP_D7 3 135 | 136 | #ifndef BREWPI_INVERT_ACTUATORS 137 | #define BREWPI_INVERT_ACTUATORS 0 138 | #endif 139 | 140 | 141 | #endif 142 | 143 | // You can use the internal pull-up resistors instead of external ones for the doorPin and the rotary encoder pins 144 | #ifndef USE_INTERNAL_PULL_UP_RESISTORS 145 | #define USE_INTERNAL_PULL_UP_RESISTORS 1 146 | #endif -------------------------------------------------------------------------------- /src/PromServer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifdef ENABLE_PROMETHEUS_SERVER 3 | #include "Brewpi.h" 4 | #include "TemperatureFormats.h" 5 | #include "Ticks.h" 6 | 7 | #if defined(ESP32) 8 | #include "AsyncTCP.h" 9 | #else 10 | #include "ESPAsyncTCP.h" 11 | #endif 12 | 13 | #include "ESPAsyncWebServer.h" 14 | 15 | /** 16 | * \brief A server for handling Prometheus metrics endpoint 17 | * 18 | * Implements the Prometheus [metrics 19 | * format](https://prometheus.io/docs/instrumenting/exposition_formats/). 20 | * Allows data gathering using an industry standard metrics system. This opens 21 | * the possibility of more powerful reporting & alerting. 22 | * 23 | * Because enumerating and reading probes can take a relatively long time, this 24 | * class implements a cache so that subsequent data requests will use the 25 | * cached value. This cache only applies to the probe values, not the entire 26 | * metrics response. External code can use PromServer::invalidateCache() to 27 | * force cache updates. 28 | */ 29 | class PromServer { 30 | public: 31 | void setup(); 32 | static void onNotFound(AsyncWebServerRequest *request); 33 | static void metrics(AsyncWebServerRequest *request); 34 | static String templateProcessor(const String &var); 35 | static void invalidateCache(); 36 | 37 | private: 38 | /** 39 | * \brief ESPAsyncWebServer connection listener. 40 | * 41 | * Handles incoming requests to the Prometheus port and dispatches to handler 42 | * methods. 43 | * \see https://github.com/me-no-dev/ESPAsyncWebServer 44 | */ 45 | AsyncWebServer server = AsyncWebServer(Config::Prometheus::port); 46 | static String probeCache; 47 | 48 | /** 49 | * \brief Template string for the metrics data. 50 | * 51 | * Placeholders values (surrounded by `%` chars) are replaced at runtime using 52 | * PromServer::templateProcessor(). 53 | * 54 | * \see templateProcessor() 55 | */ 56 | static const char metricsTemplate[]; 57 | 58 | /** 59 | * \brief Template for an individual probe value 60 | * 61 | * Used to fill the PROBE_VALUES section of metricsTemplate for each 62 | * enumerated probe. 63 | * 64 | * \see probeValues() 65 | */ 66 | static const char probeTemplate[]; 67 | 68 | static String formatProbeTemp(const temperature temp); 69 | static String probeValues(); 70 | 71 | /** 72 | * \brief How long to cache probe readings 73 | */ 74 | static constexpr auto cacheTime = 300; 75 | 76 | /** 77 | * \brief Tick count of the last time the probe cache was built. 78 | * 79 | * Used to track the expiration of the probe cache. 80 | */ 81 | static ticks_seconds_t dataLastUpdate; 82 | }; 83 | 84 | extern PromServer promServer; 85 | #endif // ENABLE_PROMETHEUS_SERVER 86 | -------------------------------------------------------------------------------- /src/Random.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * 4 | * This file is part of BrewPi. 5 | * 6 | * BrewPi is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BrewPi is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BrewPi. If not, see . 18 | */ 19 | 20 | #ifndef BREWPI_RANDOM 21 | #define BREWPI_RANDOM 1 22 | #endif 23 | 24 | #if BREWPI_RANDOM 25 | // Have to include this separately from Arduino.h, since it redefines makeWord() 26 | #include 27 | 28 | #endif -------------------------------------------------------------------------------- /src/RotaryEncoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * 4 | * This file is part of BrewPi. 5 | * 6 | * BrewPi is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BrewPi is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BrewPi. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "Brewpi.h" 23 | 24 | // Values returned by 'process' 25 | // No complete step yet. 26 | #define DIR_NONE 0x0 27 | // Clockwise step. 28 | #define DIR_CW 0x10 29 | // Anti-clockwise step. 30 | #define DIR_CCW 0x20 31 | 32 | class RotaryEncoder 33 | { 34 | public: 35 | static void init(); 36 | static void setRange(int16_t start, int16_t min, int16_t max); 37 | static void process(); 38 | 39 | static bool changed(); // returns one if the value changed since the last call of changed. 40 | static int16_t read(); 41 | 42 | static int16_t readsteps(){ 43 | return steps; 44 | } 45 | 46 | static bool pushed(){ 47 | return pushFlag; 48 | } 49 | 50 | static void resetPushed(){ 51 | pushFlag = false; 52 | } 53 | 54 | static void setPushed(); 55 | 56 | private: 57 | 58 | static int16_t maximum; 59 | static int16_t minimum; 60 | static volatile int16_t steps; 61 | static volatile bool pushFlag; 62 | }; 63 | 64 | extern RotaryEncoder rotaryEncoder; 65 | -------------------------------------------------------------------------------- /src/Sensor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #include "Brewpi.h" 22 | #include "Sensor.h" 23 | -------------------------------------------------------------------------------- /src/Sensor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "Brewpi.h" 24 | 25 | template class Sensor 26 | { 27 | public: 28 | virtual T sense()=0; 29 | 30 | virtual ~Sensor() {} 31 | }; 32 | 33 | template 34 | class ValueSensor : public Sensor 35 | { 36 | public: 37 | ValueSensor(T initial) : value(initial) {} 38 | 39 | virtual T sense() { 40 | return (T)0; 41 | } 42 | 43 | void setValue(T _value) { 44 | value = _value; 45 | } 46 | 47 | private: 48 | T value; 49 | }; 50 | 51 | typedef Sensor SwitchSensor; 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/SensorArduinoPin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: SensorArduinoPin.h 3 | * Author: mat 4 | * 5 | * Created on 22 August 2013, 19:36 6 | */ 7 | 8 | #pragma once 9 | 10 | #ifdef ARDUINO 11 | 12 | #include "Brewpi.h" 13 | #include "FastDigitalPin.h" 14 | #include "Pins.h" 15 | 16 | /* A SwitchSensor whose state is provided by a hardware pin. 17 | By using a template, the compiler can inline and optimize the call to digitalRead to a single instruction. 18 | */ 19 | template 20 | class DigitalConstantPinSensor : public SwitchSensor 21 | { 22 | public: 23 | DigitalConstantPinSensor() { 24 | fastPinMode(pin, internalPullup ? INPUT_PULLUP : INPUT); 25 | } 26 | 27 | virtual bool sense() { 28 | return fastDigitalRead(pin) ^ invert; 29 | } 30 | }; 31 | 32 | class DigitalPinSensor : public SwitchSensor 33 | { 34 | private: 35 | bool invert; 36 | uint8_t pin; 37 | 38 | 39 | 40 | public: 41 | 42 | DigitalPinSensor(uint8_t pin, bool invert) 43 | { 44 | pinMode(pin, USE_INTERNAL_PULL_UP_RESISTORS ? INPUT_PULLUP : INPUT); 45 | this->invert = invert; 46 | this->pin = pin; 47 | } 48 | 49 | virtual bool sense() { 50 | return digitalRead(pin) ^ invert; 51 | } 52 | }; 53 | 54 | #endif 55 | 56 | -------------------------------------------------------------------------------- /src/SettingLoader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * Copyright 2020 Scott Peshak 5 | * 6 | * This file is part of BrewPi. 7 | * 8 | * BrewPi is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * BrewPi is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with BrewPi. If not, see . 20 | */ 21 | #pragma once 22 | 23 | #include "Brewpi.h" 24 | #include 25 | 26 | class SettingLoader { 27 | public: 28 | static void processSettingKeypair(JsonPair kv); 29 | 30 | private: 31 | static void setBeerSetting(const char *val); 32 | static void setFridgeSetting(const char *val); 33 | }; 34 | -------------------------------------------------------------------------------- /src/SettingsManager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later v7ersion. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #include "Brewpi.h" 22 | #include "SettingsManager.h" 23 | #include "TempControl.h" 24 | #include "PiLink.h" 25 | #include "TempSensorExternal.h" 26 | 27 | void SettingsManager::loadSettings() 28 | { 29 | logDebug("loading settings"); 30 | 31 | 32 | if (!eepromManager.applySettings()) 33 | { 34 | TempControl::loadDefaultSettings(); 35 | TempControl::loadDefaultConstants(); 36 | minTimes.setDefaults(); 37 | 38 | deviceManager.setupUnconfiguredDevices(); 39 | 40 | logWarning(WARNING_START_IN_SAFE_MODE); 41 | } 42 | 43 | #if (BREWPI_SIMULATE) 44 | { 45 | logDebug("Setting up simulator devices."); 46 | 47 | // temp sensors are special in the simulator - make sure they are set up even if not 48 | // configured in the eeprom 49 | DeviceConfig cfg; 50 | cfg.deviceHardware = DEVICE_HARDWARE_ONEWIRE_TEMP; 51 | cfg.chamber = 1; 52 | cfg.deviceFunction = DEVICE_CHAMBER_ROOM_TEMP; 53 | deviceManager.uninstallDevice(cfg); 54 | deviceManager.installDevice(cfg); 55 | 56 | cfg.deviceFunction = DEVICE_CHAMBER_TEMP; 57 | deviceManager.uninstallDevice(cfg); 58 | deviceManager.installDevice(cfg); 59 | 60 | cfg.beer = 1; 61 | cfg.deviceFunction = DEVICE_BEER_TEMP; 62 | deviceManager.uninstallDevice(cfg); 63 | deviceManager.installDevice(cfg); 64 | 65 | } 66 | #endif 67 | 68 | } 69 | 70 | SettingsManager settingsManager; -------------------------------------------------------------------------------- /src/SettingsManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "Brewpi.h" 24 | #include 25 | #include "EepromManager.h" 26 | #include "DeviceManager.h" 27 | 28 | /** 29 | * \brief Manages the settings and devices for multiple carboys and multiple chambers. 30 | * 31 | * This is the soul of brewpi. 32 | * 33 | * The manager hides the persistence of the settings, and uses the code closest to the settings to provide 34 | * useful defaults. 35 | */ 36 | class SettingsManager 37 | { 38 | public: 39 | /** 40 | * \brief Initialize settings. 41 | * 42 | * This attempts to read from persisted settings and apply settings from there. 43 | * If that's not possible, defaults are used. 44 | */ 45 | static void loadSettings(); 46 | }; 47 | 48 | extern SettingsManager settingsManager; 49 | -------------------------------------------------------------------------------- /src/TempSensor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * 4 | * This file is part of BrewPi. 5 | * 6 | * BrewPi is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BrewPi is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BrewPi. If not, see . 18 | */ 19 | 20 | #include "Brewpi.h" 21 | #include "TempSensor.h" 22 | #include "PiLink.h" 23 | #include "Ticks.h" 24 | 25 | 26 | /** 27 | * \brief Initialize temp sensor 28 | */ 29 | void TempSensor::init() 30 | { 31 | logDebug("tempsensor::init - begin %d", failedReadCount); 32 | if (_sensor && _sensor->init() && (failedReadCount<0 || failedReadCount>60)) { 33 | temperature temp = _sensor->read(); 34 | if (temp!=TEMP_SENSOR_DISCONNECTED) { 35 | logDebug("initializing filters with value %d", temp); 36 | fastFilter.init(temp); 37 | slowFilter.init(temp); 38 | slopeFilter.init(0); 39 | prevOutputForSlope = slowFilter.readOutputDoublePrecision(); 40 | failedReadCount = 0; 41 | } 42 | } 43 | } 44 | 45 | /** 46 | * \brief Read the sensor and update the filters 47 | */ 48 | void TempSensor::update() 49 | { 50 | temperature temp; 51 | if (!_sensor || (temp=_sensor->read())==TEMP_SENSOR_DISCONNECTED) { 52 | if(failedReadCount >= 0) 53 | failedReadCount++; 54 | failedReadCount = min(failedReadCount,int8_t(127)); // limit 55 | return; 56 | } 57 | 58 | fastFilter.add(temp); 59 | slowFilter.add(temp); 60 | 61 | // update slope filter every 3 samples. 62 | // averaged differences will give the slope. Use the slow filter as input 63 | updateCounter--; 64 | // initialize first read for slope filter after (255-4) seconds. This prevents an influence for the startup inaccuracy. 65 | if(updateCounter == 4){ 66 | // only happens once after startup. 67 | prevOutputForSlope = slowFilter.readOutputDoublePrecision(); 68 | } 69 | if(updateCounter == 0){ 70 | temperature_precise slowFilterOutput = slowFilter.readOutputDoublePrecision(); 71 | temperature_precise diff = slowFilterOutput - prevOutputForSlope; 72 | temperature diff_upper = diff >> 16; 73 | if(diff_upper > 27){ // limit to prevent overflow INT_MAX/1200 = 27.14 74 | diff = (27l << 16); 75 | } 76 | else if(diff_upper < -27){ 77 | diff = (-27l << 16); 78 | } 79 | slopeFilter.addDoublePrecision(1200*diff); // Multiply by 1200 (1h/4s), shift to single precision 80 | prevOutputForSlope = slowFilterOutput; 81 | updateCounter = 3; 82 | } 83 | } 84 | 85 | /** 86 | * \brief Read the sensor value after processing through the fast filter 87 | */ 88 | temperature TempSensor::readFastFiltered(){ 89 | return fastFilter.readOutput(); //return most recent unfiltered value 90 | } 91 | 92 | /** 93 | * \brief Read the sensor value after processing through the slow filter 94 | */ 95 | temperature TempSensor::readSlowFiltered(){ 96 | return slowFilter.readOutput(); //return most recent unfiltered value 97 | } 98 | 99 | /** 100 | * \brief Read the sensor value after processing through the slope filter 101 | */ 102 | temperature TempSensor::readSlope(){ 103 | // return slope per hour. 104 | temperature_precise doublePrecision = slopeFilter.readOutputDoublePrecision(); 105 | return doublePrecision>>16; // shift to single precision 106 | } 107 | 108 | 109 | /** 110 | * \brief Detect the positive peak 111 | * 112 | * Uses the detectPosPeak() method of the slow filter 113 | */ 114 | temperature TempSensor::detectPosPeak(){ 115 | return slowFilter.detectPosPeak(); 116 | } 117 | 118 | 119 | /** 120 | * \brief Detect the negative peak 121 | * 122 | * Uses the detectNegPeak() method of the slow filter 123 | */ 124 | temperature TempSensor::detectNegPeak(){ 125 | return slowFilter.detectNegPeak(); 126 | } 127 | 128 | /** 129 | * \brief Set the b coefficients on the fast filter 130 | * 131 | * @param b - New coefficient value 132 | */ 133 | void TempSensor::setFastFilterCoefficients(uint8_t b){ 134 | fastFilter.setCoefficients(b); 135 | } 136 | 137 | 138 | /** 139 | * \brief Set the b coefficients on the slow filter 140 | * 141 | * @param b - New coefficient value 142 | */ 143 | void TempSensor::setSlowFilterCoefficients(uint8_t b){ 144 | slowFilter.setCoefficients(b); 145 | } 146 | 147 | 148 | /** 149 | * \brief Set the b coefficients on the slope filter 150 | * 151 | * @param b - New coefficient value 152 | */ 153 | void TempSensor::setSlopeFilterCoefficients(uint8_t b){ 154 | slopeFilter.setCoefficients(b); 155 | } 156 | 157 | /** 158 | * \brief Get wrapped sensor 159 | */ 160 | BasicTempSensor& TempSensor::sensor() { 161 | return *_sensor; 162 | } 163 | -------------------------------------------------------------------------------- /src/TempSensor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "Brewpi.h" 24 | #include "FilterCascaded.h" 25 | #include "TempSensorBasic.h" 26 | #include 27 | 28 | #define TEMP_SENSOR_DISCONNECTED INVALID_TEMP 29 | 30 | #ifndef TEMP_SENSOR_CASCADED_FILTER 31 | #define TEMP_SENSOR_CASCADED_FILTER 1 32 | #endif 33 | 34 | #if TEMP_SENSOR_CASCADED_FILTER 35 | typedef CascadedFilter TempSensorFilter; 36 | #else 37 | typedef FixedFilter TempSensorFilter; 38 | #endif 39 | 40 | 41 | /** 42 | * \brief Types of temp sensors, defined by their use. 43 | */ 44 | enum TempSensorType { 45 | TEMP_SENSOR_TYPE_FRIDGE=1, 46 | TEMP_SENSOR_TYPE_BEER 47 | }; 48 | 49 | 50 | /** 51 | * \brief General interface for all temperature sensor devices. 52 | * 53 | * Wraps up a BasicTempSensor and processes the values through several filters. 54 | * The filters are either CascadedFilter or FixedFilter implementations, 55 | * depending on the compile time value of the TEMP_SENSOR_CASCADED_FILTER 56 | * macro. 57 | */ 58 | class TempSensor { 59 | public: 60 | TempSensor(TempSensorType sensorType, BasicTempSensor* sensor =NULL) { 61 | updateCounter = 255; // first update for slope filter after (255-4s) 62 | setSensor(sensor); 63 | } 64 | 65 | /** 66 | * \brief Set the underlying BasicTempSensor 67 | * 68 | * @param sensor - Temp sensor to wrap 69 | */ 70 | void setSensor(BasicTempSensor* sensor) { 71 | _sensor = sensor; 72 | failedReadCount = -1; 73 | } 74 | 75 | /** 76 | * \brief Check if the sensor has a slow filter. 77 | */ 78 | bool hasSlowFilter() { return true; } 79 | 80 | /** 81 | * \brief Check if the sensor has a fast filter. 82 | */ 83 | bool hasFastFilter() { return true; } 84 | 85 | /** 86 | * \brief Check if the sensor has a slope filter. 87 | */ 88 | bool hasSlopeFilter() { return true; } 89 | 90 | void init(); 91 | 92 | /** 93 | * \brief Check if the sensor is connected. 94 | */ 95 | bool isConnected() { return _sensor->isConnected(); } 96 | 97 | void update(); 98 | 99 | temperature readFastFiltered(); 100 | 101 | temperature readSlowFiltered(); 102 | 103 | temperature readSlope(); 104 | 105 | temperature detectPosPeak(); 106 | 107 | temperature detectNegPeak(); 108 | 109 | void setFastFilterCoefficients(uint8_t b); 110 | 111 | void setSlowFilterCoefficients(uint8_t b); 112 | 113 | void setSlopeFilterCoefficients(uint8_t b); 114 | 115 | BasicTempSensor& sensor(); 116 | 117 | private: 118 | BasicTempSensor* _sensor; //!< Wrapped basic sensor 119 | TempSensorFilter fastFilter; //!< Fast reacting filter 120 | TempSensorFilter slowFilter; //!< Slow reacting filter 121 | TempSensorFilter slopeFilter; //!< Slope filter 122 | unsigned char updateCounter; 123 | temperature_precise prevOutputForSlope; 124 | 125 | /** 126 | * \brief An indication of how stale the data is in the filters. 127 | * 128 | * Each time a read fails, this value is incremented. It's used to reset the 129 | * filters after a large enough disconnect delay, and on the first init. 130 | * 131 | * `-1` for uninitialized, `>=0` afterwards. 132 | */ 133 | int8_t failedReadCount; 134 | 135 | friend class ChamberManager; 136 | friend class Chamber; 137 | friend class DeviceManager; 138 | }; 139 | 140 | -------------------------------------------------------------------------------- /src/TempSensorBasic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "TemperatureFormats.h" 24 | 25 | 26 | #define TEMP_SENSOR_DISCONNECTED INVALID_TEMP 27 | 28 | 29 | /** 30 | * Temperature sensor base 31 | * Pure virtual class. 32 | */ 33 | class BasicTempSensor 34 | { 35 | public: 36 | virtual ~BasicTempSensor() { } 37 | 38 | /** 39 | * Check if sensor is connected 40 | */ 41 | virtual bool isConnected() = 0; 42 | 43 | /** 44 | * Attempt to (re-)initialize the sensor. 45 | */ 46 | virtual bool init() =0; 47 | 48 | /** 49 | * Fetch a new reading from the sensor 50 | */ 51 | virtual temperature read() = 0; 52 | }; 53 | -------------------------------------------------------------------------------- /src/TempSensorDisconnected.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "TempSensor.h" 24 | 25 | /** 26 | * A BasicTempSensor that is always disconnected. 27 | * 28 | * This is used as a default sensor to placehold until real sensors are installed. 29 | */ 30 | class DisconnectedTempSensor : public BasicTempSensor { 31 | 32 | public: 33 | bool isConnected() { return false; } 34 | 35 | bool init() { 36 | return read()!=TEMP_SENSOR_DISCONNECTED; 37 | } 38 | 39 | temperature read() { 40 | return TEMP_SENSOR_DISCONNECTED; 41 | } 42 | 43 | }; 44 | -------------------------------------------------------------------------------- /src/TempSensorExternal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "Brewpi.h" 24 | #include "TempSensor.h" 25 | 26 | /** 27 | * A temp sensor whose value is not read from the device, but set in code. 28 | * This is used by the simulator. 29 | */ 30 | class ExternalTempSensor : public BasicTempSensor 31 | { 32 | public: 33 | ExternalTempSensor(bool connected=false) : _temperature(0), _connected(false) 34 | { 35 | setConnected(connected); 36 | } 37 | 38 | void setConnected(bool connected) 39 | { 40 | this->_connected = connected; 41 | } 42 | 43 | bool isConnected() { return _connected; } 44 | 45 | bool init() { 46 | return read()!=TEMP_SENSOR_DISCONNECTED; 47 | } 48 | 49 | temperature read() { 50 | if (!isConnected()) 51 | return TEMP_SENSOR_DISCONNECTED; 52 | return _temperature; 53 | } 54 | 55 | void setValue(temperature newTemp) { 56 | _temperature = newTemp; 57 | } 58 | 59 | private: 60 | temperature _temperature; 61 | bool _connected; 62 | }; 63 | -------------------------------------------------------------------------------- /src/TempSensorMock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "Brewpi.h" 24 | #include "TempSensor.h" 25 | 26 | /** 27 | * A mock implementation of BasicTempSensor 28 | * 29 | * This is a fake temp sensor that shifts it's value on each read. 30 | */ 31 | class MockTempSensor : public BasicTempSensor 32 | { 33 | public: 34 | MockTempSensor(temperature initial, temperature delta) : _temperature(initial), _delta(delta), _connected(true) { } 35 | 36 | void setConnected(bool connected) 37 | { 38 | _connected = connected; 39 | } 40 | 41 | bool isConnected() { return _connected; } 42 | 43 | bool init() { 44 | return read()!=TEMP_SENSOR_DISCONNECTED; 45 | } 46 | 47 | /** 48 | * Return the current temperature value. 49 | * 50 | * Shifts the temp value up/down (depending on tempcontrol mode) by `_delta` on each read. 51 | */ 52 | temperature read() 53 | { 54 | if (!isConnected()) 55 | return TEMP_SENSOR_DISCONNECTED; 56 | 57 | switch (tempControl.getMode()) { 58 | case COOLING: 59 | _temperature -= _delta; 60 | break; 61 | case HEATING: 62 | _temperature += _delta; 63 | break; 64 | } 65 | 66 | return _temperature; 67 | } 68 | 69 | private: 70 | /** 71 | * Current temperature value 72 | */ 73 | temperature _temperature; 74 | 75 | /** 76 | * Delta to shift per read 77 | */ 78 | temperature _delta; 79 | bool _connected; 80 | }; 81 | 82 | -------------------------------------------------------------------------------- /src/Ticks.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #include "Brewpi.h" 22 | #include "Ticks.h" 23 | 24 | // return time that has passed since timeStamp, take overflow into account 25 | inline ticks_seconds_t timeSince(ticks_seconds_t currentTime, ticks_seconds_t previousTime){ 26 | if(currentTime>=previousTime){ 27 | return currentTime - previousTime; 28 | } 29 | else{ 30 | // overflow has occurred 31 | return (currentTime + 1440) - (previousTime +1440); // add a day to both for calculation 32 | } 33 | } 34 | 35 | // return time that has passed since timeStamp, take overflow into account 36 | ticks_seconds_t ExternalTicks::timeSince(ticks_seconds_t previousTime){ 37 | ticks_seconds_t currentTime = ticks.seconds(); 38 | return ::timeSince(currentTime, previousTime); 39 | } 40 | 41 | 42 | #ifdef ARDUINO 43 | 44 | // return time that has passed since timeStamp, take overflow into account 45 | ticks_seconds_t HardwareTicks::timeSince(ticks_seconds_t previousTime){ 46 | ticks_seconds_t currentTime = ticks.seconds(); 47 | return ::timeSince(currentTime, previousTime); 48 | } 49 | 50 | ticks_seconds_t HardwareTicks::seconds() { return ::millis()/1000; } 51 | 52 | 53 | void HardwareDelay::millis(uint16_t millis) { ::delay(millis); } 54 | 55 | void HardwareDelay::seconds(uint16_t seconds) { millis(seconds<<10); } 56 | 57 | #endif -------------------------------------------------------------------------------- /src/Ticks.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "Brewpi.h" 24 | 25 | typedef uint32_t ticks_millis_t; 26 | typedef uint32_t ticks_micros_t; 27 | typedef uint16_t ticks_seconds_t; 28 | typedef uint8_t ticks_seconds_tiny_t; 29 | 30 | /** 31 | * Ticks - interface to a millisecond timer 32 | * 33 | * With more code space, Ticks would have been a virtual base class, so all implementations can easily provide the same interface. 34 | * Here, the different implementations have no common (virtual) base class to save code space. 35 | * Instead, a typedef is used to compile-time select the implementation to use. 36 | * If that implementation doesn't implement the Ticks interface as expected, it will fail to compile. 37 | */ 38 | 39 | /** 40 | * A Ticks implementation that increments the millis count each time it is called. 41 | * This is used for testing. 42 | */ 43 | class MockTicks { 44 | public: 45 | MockTicks(uint8_t increment) : _increment(increment), _ticks(0) { } 46 | 47 | ticks_millis_t millis() { return _ticks+=_increment; } 48 | ticks_micros_t micros() { return _ticks+=_increment; } 49 | ticks_seconds_t seconds() { return millis()>>10; } 50 | ticks_seconds_t timeSince(ticks_seconds_t timeStamp) { return timeStamp-seconds(); } 51 | private: 52 | 53 | uint32_t _increment; 54 | uint32_t _ticks; 55 | }; 56 | 57 | /** 58 | * Externally provided millis timer. The calling code takes care of advancing the timer by calling setMillis or incMillis. 59 | * This is used for testing and also by the simulator to provide simulated time. 60 | */ 61 | class ExternalTicks { 62 | public: 63 | ExternalTicks() : _ticks(0) { } 64 | 65 | ticks_millis_t millis() { return _ticks; } 66 | ticks_micros_t micros() { return _ticks*1000; } 67 | ticks_seconds_t seconds() { return millis()/1000; } 68 | ticks_seconds_t timeSince(ticks_seconds_t timeStamp); 69 | 70 | void setMillis(ticks_millis_t now) { _ticks = now; } 71 | void incMillis(ticks_millis_t advance) { _ticks += advance; } 72 | private: 73 | ticks_millis_t _ticks; 74 | }; 75 | 76 | 77 | /** 78 | * A delay class that does nothing. 79 | * In the AVR simulator, delays using millis() take a very long time. Using this class makes it possible to step through the code. 80 | */ 81 | class NoOpDelay { 82 | public: 83 | void seconds(uint16_t seconds) { millis(seconds<<10); } 84 | void millis(uint32_t millis) { } 85 | void microseconds(uint32_t micros) { } 86 | }; 87 | 88 | #include "TicksArduino.h" 89 | 90 | // Determine the type of Ticks needed 91 | // TICKS_IMPL_CONFIG is the code string passed to the constructor of the Ticks implementation 92 | 93 | #if BREWPI_SIMULATE 94 | /** For simulation, by the simulator - each step in the simulator advances the time by one second. */ 95 | typedef ExternalTicks TicksImpl; 96 | #define TICKS_IMPL_CONFIG // no configuration of ExternalTicks necessary 97 | 98 | #elif BREWPI_EMULATE 99 | /** When debugging in AVR studio (and running normal brewpi - not the simulator), use a simple MockTicks that increments 100 100 | millis each time it's called. */ 101 | typedef MockTicks TicksImpl; 102 | #define TICKS_IMPL_CONFIG 100 103 | 104 | #else // use regular hardware timer/delay 105 | typedef HardwareTicks TicksImpl; 106 | #define TICKS_IMPL_CONFIG 107 | #endif // BREWPI_EMULATE 108 | 109 | extern TicksImpl ticks; 110 | 111 | // Determine the type of delay required. 112 | // For emulation, don't delay, since time in the emulator is not real time, so the delay is meaningless. 113 | // For regular code, use the arduino delay function. 114 | 115 | #if BREWPI_EMULATE || !defined(ARDUINO) 116 | typedef NoOpDelay DelayImpl; // for emulation (avr debugger), don't bother delaying, it takes ages. 117 | #define DELAY_IMPL_CONFIG 118 | #else 119 | typedef HardwareDelay DelayImpl; 120 | #define DELAY_IMPL_CONFIG 121 | #endif 122 | 123 | extern DelayImpl wait; 124 | -------------------------------------------------------------------------------- /src/TicksArduino.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 BrewPi/Elco Jacobs. 3 | * Copyright 2013 Matthew McGowan. 4 | * 5 | * This file is part of BrewPi. 6 | * 7 | * BrewPi is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BrewPi is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BrewPi. If not, see . 19 | */ 20 | 21 | #pragma once 22 | 23 | #ifdef ARDUINO 24 | 25 | #include "Brewpi.h" 26 | 27 | /* 28 | * The Ticks class provides the time period since the device was powered up. 29 | */ 30 | class HardwareTicks { 31 | public: 32 | ticks_millis_t millis() { return ::millis(); } 33 | ticks_micros_t micros() { return ::micros(); } 34 | ticks_seconds_t seconds(); 35 | 36 | ticks_seconds_t timeSince(ticks_seconds_t timeStamp); 37 | }; 38 | 39 | 40 | class HardwareDelay { 41 | public: 42 | HardwareDelay() {} 43 | void seconds(uint16_t seconds); 44 | void millis(uint16_t millis); 45 | void microseconds(uint32_t micros) { ::delayMicroseconds(micros); } 46 | }; 47 | 48 | #endif -------------------------------------------------------------------------------- /src/TiltTempSensor.cpp: -------------------------------------------------------------------------------- 1 | #ifdef HAS_BLUETOOTH 2 | #include "Brewpi.h" 3 | #include "TiltTempSensor.h" 4 | #include "PiLink.h" // For printBytes 5 | #include "TemperatureFormats.h" 6 | 7 | #include "wireless/BTScanner.h" 8 | 9 | TiltTempSensor::~TiltTempSensor(){ 10 | // delete sensor; 11 | }; 12 | 13 | /** 14 | * \brief Initializes the temperature sensor. 15 | * 16 | * This method is called when the sensor is first created and also any time the 17 | * sensor reports it's disconnected. If the result is TEMP_SENSOR_DISCONNECTED 18 | * then subsequent calls to read() will also return TEMP_SENSOR_DISCONNECTED. 19 | * Clients should attempt to re-initialize the sensor by calling init() again. 20 | */ 21 | bool TiltTempSensor::init() { 22 | if (th==NULL) { 23 | th = bt_scanner.get_or_create_tilt(btAddress); 24 | if (th==NULL) { 25 | logErrorString(ERROR_SRAM_SENSOR, btAddress.toString().c_str()); 26 | } 27 | } 28 | return isConnected(); 29 | } 30 | 31 | 32 | /** 33 | * \brief Read the value of the sensor 34 | * 35 | * @return TEMP_SENSOR_DISCONNECTED if sensor is not connected, constrained temp otherwise. 36 | * @see readAndConstrainTemp() 37 | */ 38 | temperature TiltTempSensor::read(){ 39 | if (!isConnected()) 40 | return TEMP_SENSOR_DISCONNECTED; 41 | 42 | return readAndConstrainTemp(); 43 | } 44 | 45 | 46 | /** 47 | * \brief Reads the temperature. 48 | * 49 | * If successful, constrains the temp to the range of the temperature type 50 | * and updates lastRequestTime. On successful, leaves lastRequestTime alone 51 | * and returns TEMP_SENSOR_DISCONNECTED. 52 | */ 53 | temperature TiltTempSensor::readAndConstrainTemp() 54 | { 55 | if(!isConnected()) { 56 | return TEMP_SENSOR_DISCONNECTED; 57 | } 58 | 59 | // double rawTemp = ib->getTemp() / 1000; 60 | // temperature temp = doubleToTemp(rawTemp); 61 | 62 | // const uint8_t shift = TEMP_FIXED_POINT_BITS - sensorPrecision; // difference in precision between DS18B20 format and temperature adt 63 | // temp = constrainTemp(temp+calibrationOffset+(C_OFFSET>>shift), ((int) MIN_TEMP)>>shift, ((int) MAX_TEMP)>>shift)<getTempFixedPoint() + (calibrationOffset<<(TEMP_FIXED_POINT_BITS - TEMP_CALIBRATION_OFFSET_PRECISION)), MIN_TEMP, MAX_TEMP); 66 | return temp; 67 | } 68 | #endif 69 | -------------------------------------------------------------------------------- /src/TiltTempSensor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifdef HAS_BLUETOOTH 3 | #include "Brewpi.h" 4 | #include "TempSensor.h" 5 | #include "FastDigitalPin.h" 6 | #include "Ticks.h" 7 | #include 8 | 9 | #include "wireless/Tilt.h" 10 | 11 | 12 | /** 13 | * \brief A Tilt bluetooth temperature sensor 14 | * 15 | * \ingroup hardware 16 | */ 17 | class TiltTempSensor : public BasicTempSensor { 18 | public: 19 | /** 20 | * \brief Constructs a new Tilt temp sensor. 21 | * 22 | * /param address The MAC address for this sensor. 23 | * /param calibration A temperature value that is added to all readings. This can be used to calibrate the sensor. 24 | */ 25 | TiltTempSensor(NimBLEAddress address, fixed4_4 calibrationOffset) { 26 | btAddress = address; 27 | 28 | this->calibrationOffset = calibrationOffset; 29 | th = nullptr; 30 | }; 31 | 32 | ~TiltTempSensor(); 33 | 34 | /** 35 | * \brief Check if sensor device is connected 36 | */ 37 | bool isConnected(){ 38 | if (th && th->isConnected()) 39 | return true; 40 | return false; 41 | } 42 | 43 | bool init(); 44 | temperature read(); 45 | 46 | NimBLEAddress btAddress; 47 | tilt *th; 48 | 49 | private: 50 | /** 51 | * \brief The sensor precision, in bits. 52 | */ 53 | // constexpr static uint8_t sensorPrecision = 4; 54 | 55 | temperature readAndConstrainTemp(); 56 | // uint8_t sensorAddress[6]; 57 | 58 | fixed4_4 calibrationOffset; //!< Temperature offset needed for calibration 59 | 60 | }; 61 | #endif -------------------------------------------------------------------------------- /src/http_server.h: -------------------------------------------------------------------------------- 1 | #ifndef BREWPI_HTTP_SERVER_H 2 | #define BREWPI_HTTP_SERVER_H 3 | 4 | #ifdef ENABLE_HTTP_INTERFACE 5 | 6 | #define WEB_SERVER_PORT 80 7 | 8 | #ifdef ESP8266 9 | #include 10 | #define WEBSERVER_IMPL ESP8266WebServer 11 | #elif defined(ESP32) 12 | #include 13 | #define WEBSERVER_IMPL WebServer 14 | #endif 15 | 16 | 17 | uint8_t processUpstreamConfigUpdateJson(const JsonDocument& json, bool triggerUpstreamUpdate = true); 18 | 19 | 20 | class httpServer { 21 | public: 22 | void init(); 23 | //void handleClient(); 24 | bool lcd_reinit_rqd = false; 25 | bool restart_requested = false; 26 | bool name_reset_requested = false; 27 | bool wifi_reset_requested = false; 28 | bool config_reset_requested = false; 29 | bool ota_update_requested = false; 30 | WEBSERVER_IMPL *web_server; 31 | 32 | 33 | private: 34 | void uptime(); 35 | void heap(); 36 | void genericServeJson(void(*jsonFunc)(DynamicJsonDocument&)); 37 | void processJsonRequest(const char* uri, uint8_t (*handler)(const DynamicJsonDocument& json, bool triggerUpstreamUpdate)); 38 | void serveExtendedSettings(); 39 | void serveUpstreamSettings(); 40 | void serveMinTimes(); 41 | void reset_reason(); 42 | 43 | void setStaticPages(); 44 | void setJsonPages(); 45 | void setJsonHandlers(); 46 | 47 | String getContentType(String filename); 48 | // bool exists(String path); 49 | bool handleFileRead(String path); 50 | void redirect(const String& url); 51 | 52 | }; 53 | 54 | extern httpServer http_server; 55 | 56 | #endif //ENABLE_HTTP_INTERFACE 57 | 58 | #endif //TRONBRIDGE_HTTP_SERVER_H 59 | -------------------------------------------------------------------------------- /src/http_server_generic.cpp: -------------------------------------------------------------------------------- 1 | #ifdef ENABLE_HTTP_INTERFACE 2 | 3 | #include 4 | #include 5 | #include "ESPEepromAccess.h" 6 | 7 | #include "http_server.h" 8 | 9 | 10 | 11 | // Functions needed to serve static files 12 | String httpServer::getContentType(String filename) { 13 | if (web_server->hasArg("download")) { 14 | return "application/octet-stream"; 15 | } else if (filename.endsWith(".htm")) { 16 | return "text/html"; 17 | } else if (filename.endsWith(".html")) { 18 | return "text/html"; 19 | } else if (filename.endsWith(".css")) { 20 | return "text/css"; 21 | } else if (filename.endsWith(".js")) { 22 | return "application/javascript"; 23 | } else if (filename.endsWith(".png")) { 24 | return "image/png"; 25 | } else if (filename.endsWith(".gif")) { 26 | return "image/gif"; 27 | } else if (filename.endsWith(".jpg")) { 28 | return "image/jpeg"; 29 | } else if (filename.endsWith(".ico")) { 30 | return "image/x-icon"; 31 | } else if (filename.endsWith(".xml")) { 32 | return "text/xml"; 33 | } else if (filename.endsWith(".pdf")) { 34 | return "application/x-pdf"; 35 | } else if (filename.endsWith(".zip")) { 36 | return "application/x-zip"; 37 | } else if (filename.endsWith(".gz")) { 38 | return "application/x-gzip"; 39 | } else if (filename.endsWith(".svg")) { 40 | return "image/svg+xml"; 41 | } 42 | return "text/plain"; 43 | } 44 | 45 | // bool httpServer::exists(String path){ 46 | // bool yes = false; 47 | // File file = FILESYSTEM.open(path, "r"); 48 | // if(!file.isDirectory()){ 49 | // yes = true; 50 | // } 51 | // file.close(); 52 | // return yes; 53 | // } 54 | 55 | bool httpServer::handleFileRead(String path) { 56 | // Serial.println("handleFileRead: " + path); 57 | if (path.endsWith("/")) { 58 | path += "index.htm"; 59 | } 60 | String contentType = getContentType(path); 61 | String pathWithGz = path + ".gz"; 62 | if (FILESYSTEM.exists(pathWithGz) || FILESYSTEM.exists(path)) { 63 | if (FILESYSTEM.exists(pathWithGz)) { 64 | path += ".gz"; 65 | } 66 | File file = FILESYSTEM.open(path, "r"); 67 | web_server->streamFile(file, contentType); 68 | file.close(); 69 | return true; 70 | } 71 | return false; 72 | } 73 | 74 | void httpServer::redirect(const String& url){ 75 | web_server->sendHeader("Location", url); 76 | web_server->sendHeader("Cache-Control", "no-cache"); 77 | web_server->send(302); 78 | return; 79 | } 80 | 81 | #endif // ENABLE_HTTP_INTERFACE 82 | -------------------------------------------------------------------------------- /src/resetreasons.h: -------------------------------------------------------------------------------- 1 | #ifndef _RESETREASONS_H 2 | #define _RESETREASONS_H 3 | 4 | #if defined ESP8266 5 | const char *resetReason[7] = { 6 | "REASON_DEFAULT_RST", // = 0, /* normal startup by power on */ 7 | "REASON_WDT_RST", // = 1, /* hardware watch dog reset */ 8 | "REASON_EXCEPTION_RST", // = 2, /* exception reset, GPIO status won’t change */ 9 | "REASON_SOFT_WDT_RST", // = 3, /* software watch dog reset, GPIO status won’t change */ 10 | "REASON_SOFT_RESTART", // = 4, /* software restart ,system_restart , GPIO status won’t change */ 11 | "REASON_DEEP_SLEEP_AWAKE", // = 5, /* wake up from deep-sleep */ 12 | "REASON_EXT_SYS_RST" // = 6 /* external system reset */ 13 | }; 14 | 15 | const char *resetDescription[7] = { 16 | "Normal startup by power on", 17 | "Hardware watch dog reset", 18 | "Exception reset, GPIO status won’t change", 19 | "Software watch dog reset, GPIO status won’t change", 20 | "Software restart, system_restart, GPIO status won’t change", 21 | "Wake up from deep-sleep", 22 | "External system reset"}; 23 | 24 | #elif ESP32 25 | 26 | const char *resetReason[11] = { 27 | "ESP_RST_UNKNOWN", //!< Reset reason can not be determined 28 | "ESP_RST_POWERON", //!< Reset due to power-on event 29 | "ESP_RST_EXT", //!< Reset by external pin (not applicable for ESP32) 30 | "ESP_RST_SW", //!< Software reset via esp_restart 31 | "ESP_RST_PANIC", //!< Software reset due to exception/panic 32 | "ESP_RST_INT_WDT", //!< Reset (software or hardware) due to interrupt watchdog 33 | "ESP_RST_TASK_WDT", //!< Reset due to task watchdog 34 | "ESP_RST_WDT", //!< Reset due to other watchdogs 35 | "ESP_RST_DEEPSLEEP", //!< Reset after exiting deep sleep mode 36 | "ESP_RST_BROWNOUT", //!< Brownout reset (software or hardware) 37 | "ESP_RST_SDIO" //!< Reset over SDIO 38 | }; 39 | 40 | const char *resetDescription[11] = { 41 | "Reset reason can not be determined", 42 | "Reset due to power-on event", 43 | "Reset by external pin (not applicable for ESP32)", 44 | "Software reset via esp_restart", 45 | "Software reset due to exception/panic", 46 | "Reset (software or hardware) due to interrupt watchdog", 47 | "Reset due to task watchdog", 48 | "Reset due to other watchdogs", 49 | "Reset after exiting deep sleep mode", 50 | "Brownout reset (software or hardware)", 51 | "Reset over SDIO" 52 | }; 53 | 54 | #endif 55 | 56 | #endif // _RESETREASONS_H 57 | -------------------------------------------------------------------------------- /src/tplink/TPLinkConnector.h: -------------------------------------------------------------------------------- 1 | #ifndef TPLINK_KASA_TPLINKCONNECTOR_H 2 | #define TPLINK_KASA_TPLINKCONNECTOR_H 3 | 4 | #include 5 | #include 6 | 7 | #define TP_LINK_INITIALIZATION_VECTOR 171 8 | 9 | class TPLinkConnector { 10 | 11 | public: 12 | // TPLinkConnector(); 13 | // ~TPLinkConnector(); 14 | 15 | void discover(); 16 | 17 | void init_udp(); 18 | 19 | void send_payload(const IPAddress host, const std::string payload, bool include_size); 20 | void broadcast_payload(std::string payload, bool include_size); 21 | std::string receive_udp(); 22 | std::string receive_udp(IPAddress *udp_ip); 23 | 24 | // private: 25 | static std::string encrypt(std::string unencr, bool include_size); 26 | static std::string decrypt(std::string encr); 27 | 28 | private: 29 | //The udp library class 30 | WiFiUDP udp; 31 | 32 | }; 33 | 34 | 35 | #endif //TPLINK_KASA_TPLINKCONNECTOR_H 36 | -------------------------------------------------------------------------------- /src/tplink/TPLinkDevice.cpp: -------------------------------------------------------------------------------- 1 | #include "TPLinkDevice.h" 2 | 3 | void TPLinkDevice::send_payload(const std::string payload, bool include_size) { 4 | // This is a thin wrapper around tp_link_connector's send_payload that just adds the IP address to the send request 5 | tp_link_connector->send_payload(ip_addr, payload, include_size); 6 | } -------------------------------------------------------------------------------- /src/tplink/TPLinkDevice.h: -------------------------------------------------------------------------------- 1 | #ifndef TPLINK_KASA_TPLINKDEVICE_H 2 | #define TPLINK_KASA_TPLINKDEVICE_H 3 | 4 | #include 5 | #include "TPLinkConnector.h" 6 | #include 7 | 8 | enum TPLinkDeviceType { 9 | TPLINK_KASA_SMARTPLUGSWITCH = 0 // e.g. HS103, KP400 10 | }; 11 | 12 | 13 | class TPLinkDevice { 14 | public: 15 | IPAddress ip_addr; 16 | TPLinkDeviceType type; 17 | 18 | char device_mac[18]; 19 | char device_alias[32]; 20 | char device_id[41]; 21 | 22 | protected: 23 | TPLinkConnector* tp_link_connector; 24 | void send_payload(const std::string payload, bool include_size); 25 | }; 26 | 27 | 28 | #endif //TPLINK_KASA_TPLINKDEVICE_H 29 | -------------------------------------------------------------------------------- /src/tplink/TPLinkPlug.h: -------------------------------------------------------------------------------- 1 | #ifndef TPLINK_KASA_TPLINKPLUG_H 2 | #define TPLINK_KASA_TPLINKPLUG_H 3 | 4 | #include 5 | #include "TPLinkDevice.h" 6 | 7 | 8 | class TPLinkPlug : public TPLinkDevice { 9 | 10 | public: 11 | TPLinkPlug(IPAddress ip, const char * deviceMAC, const char * deviceID, const char * childID, TPLinkConnector* tplink_conn); 12 | TPLinkPlug(IPAddress ip, const char * deviceMAC, const char * deviceID, const char * childID, const char * devAlias, TPLinkConnector* tplink_conn); 13 | 14 | bool last_read_on; 15 | 16 | bool set_on(); 17 | bool set_off(); 18 | 19 | void get_countdown(); 20 | void set_countdown(uint8_t act, uint16_t secs); 21 | void set_countdown_to_off(uint16_t secs); 22 | void set_countdown_to_on(uint16_t secs); 23 | void clear_countdown(); 24 | 25 | char child_id[3]; 26 | 27 | }; 28 | 29 | 30 | #endif //TPLINK_KASA_TPLINKPLUG_H 31 | -------------------------------------------------------------------------------- /src/tplink/TPLinkScanner.h: -------------------------------------------------------------------------------- 1 | #ifndef TPLINK_KASA_TPLINKSCANNER_H 2 | #define TPLINK_KASA_TPLINKSCANNER_H 3 | 4 | #include 5 | #include 6 | #include "TPLinkPlug.h" 7 | #include "TPLinkConnector.h" 8 | 9 | 10 | #define TPLINK_DISCOVER_EVERY 30 // How frequently to send discovery packets (in seconds) 11 | #define TPLINK_SAFETY_TIMEOUT_REFRESH 20 // How frequently to refresh the "safety" off countdown (in seconds) 12 | #define TPLINK_SAFETY_TIMEOUT (TPLINK_SAFETY_TIMEOUT_REFRESH * 3 + 5) // How long to set the "safety" off countdown to turn the device off after 13 | 14 | class TPLinkScanner { 15 | 16 | public: 17 | TPLinkConnector tplink_connector; 18 | 19 | // Device Lists 20 | std::list lTPLinkPlugs; 21 | 22 | TPLinkPlug* get_tplink_plug(const char *deviceMAC, const char *childID); 23 | TPLinkPlug* get_or_create_tplink_plug(IPAddress ip_addr, const char *deviceMAC, const char *deviceID, const char *childID, const char *alias); 24 | 25 | void init(); 26 | void process_udp_incoming(); 27 | void send_discover(); 28 | void send_refresh(); 29 | 30 | void scan_and_refresh(); 31 | 32 | uint64_t last_discover_at=0; 33 | uint64_t last_refresh_at=0; 34 | }; 35 | 36 | extern TPLinkScanner tp_link_scanner; 37 | 38 | #endif //TPLINK_KASA_TPLINKSCANNER_H 39 | -------------------------------------------------------------------------------- /src/uptime.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Lee Bussy on 12/31/20 3 | // 4 | 5 | #include "uptime.h" 6 | 7 | static int refresh = UPTIME_REFRESH * 1000; 8 | static unsigned long uptimeNow; 9 | static int days; 10 | static int hours; 11 | static int minutes; 12 | static int seconds; 13 | static int mills; 14 | 15 | void getNow() 16 | { 17 | // Set the uptime values if refresh time is expired 18 | if ((int)(millis() - uptimeNow) > refresh) 19 | { 20 | setValues(); 21 | } 22 | // Reset timer for another period to avoid a really unlikely situation 23 | // where the timer expires in between grabbing two parts 24 | uptimeNow = millis(); 25 | } 26 | 27 | void setValues() 28 | { 29 | // Call this only by getNow() 30 | // Using refr = true forces recalculation 31 | uptimeNow = millis(); 32 | days = uptimeDays(true); 33 | hours = uptimeHours(true); 34 | minutes = uptimeMinutes(true); 35 | seconds = uptimeSeconds(true); 36 | mills = uptimeMillis(true); 37 | } 38 | 39 | const int uptimeDays(bool refr) 40 | { 41 | getNow(); // Make sure we are current 42 | if (refr) 43 | { 44 | // Calculate full days from uptime 45 | days = (int)floor(uptimeNow / DAY_MILLIS); 46 | } 47 | return days; 48 | } 49 | 50 | const int uptimeHours(bool refr) 51 | { 52 | getNow(); // Make sure we are current 53 | if (refr) 54 | { 55 | // Refresh values: 56 | // Subtract millis value for any full days via modulo 57 | // Calculate full hours from remainder 58 | hours = (int)floor((uptimeNow % DAY_MILLIS) / HOUR_MILLIS); 59 | } 60 | return hours; 61 | } 62 | 63 | const int uptimeMinutes(bool refr) 64 | { 65 | getNow(); // Make sure we are current 66 | if (refr) 67 | { 68 | // Refresh values: 69 | // Subtract millis value for any full hours via modulo 70 | // Calculate full minutes from remainder 71 | minutes = (int)floor((uptimeNow % HOUR_MILLIS) / MIN_MILLIS); 72 | } 73 | return minutes; 74 | } 75 | 76 | const int uptimeSeconds(bool refr) 77 | { 78 | getNow(); // Make sure we are current 79 | if (refr) 80 | { 81 | // Refresh values: 82 | // Subtract millis value for any full minutes via modulo 83 | // Calculate full seconds from remainder 84 | seconds = (int)floor((uptimeNow % MIN_MILLIS) / SEC_MILLIS); 85 | } 86 | return seconds; 87 | } 88 | 89 | const int uptimeMillis(bool refr) 90 | { 91 | getNow(); // Make sure we are current 92 | if (refr) 93 | { 94 | // Refresh values: 95 | // Subtract millis value for any full seconds via modulo 96 | // Return remainder millis 97 | mills = (int)floor((uptimeNow % SEC_MILLIS)); 98 | } 99 | return mills; 100 | } 101 | -------------------------------------------------------------------------------- /src/uptime.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Lee Bussy on 12/31/20 3 | // 4 | 5 | #ifndef _UPTIME_H 6 | #define _UPTIME_H 7 | 8 | #include 9 | 10 | #define UPTIME_REFRESH 1 11 | 12 | #define DAY_MILLIS 86400000 13 | #define HOUR_MILLIS 3600000 14 | #define MIN_MILLIS 60000 15 | #define SEC_MILLIS 1000 16 | 17 | void getNow(); 18 | void setValues(); 19 | const int uptimeDays(bool refr = false); 20 | const int uptimeHours(bool refr = false); 21 | const int uptimeMinutes(bool refr = false); 22 | const int uptimeSeconds(bool refr = false); 23 | const int uptimeMillis(bool refr = false); 24 | 25 | #endif // _UPTIME_H 26 | -------------------------------------------------------------------------------- /src/wireless/BTScanner.h: -------------------------------------------------------------------------------- 1 | #ifndef BREWPI_BTSCANNER_H 2 | #define BREWPI_BTSCANNER_H 3 | 4 | #ifdef HAS_BLUETOOTH 5 | 6 | #include "Inkbird.h" 7 | #include "Tilt.h" 8 | 9 | #define BLE_SCAN_TIME 60 // Seconds to scan (0=continuous scanning) 10 | #define SCAN_FAIL_THRESHHOLD (5*60*1000*1000) // If we don't detect anything in 5 minutes, then the scanner failed. 11 | 12 | class btScanner 13 | { 14 | public: 15 | btScanner(); 16 | void init(); 17 | bool scan(); 18 | void stop_scan(); 19 | 20 | inkbird* get_or_create_inkbird(const NimBLEAddress devAddress); 21 | inkbird* get_inkbird(const NimBLEAddress devAddress); 22 | 23 | tilt* get_or_create_tilt(const NimBLEAddress devAddress); 24 | tilt* get_tilt(const NimBLEAddress devAddress); 25 | 26 | void purge_stale_inkbirds(); 27 | void purge_stale_tilts(); 28 | 29 | bool scanning_failed(); 30 | 31 | bool shouldRun; 32 | 33 | uint64_t last_detected_device_at; 34 | 35 | 36 | private: 37 | uint64_t m_last_inkbird_purge_at; 38 | uint64_t m_last_tilt_purge_at; 39 | 40 | }; 41 | 42 | 43 | extern btScanner bt_scanner; 44 | extern std::list lInkbirds; 45 | extern std::list lTilts; 46 | 47 | 48 | #endif // HAS_BLUETOOTH 49 | 50 | #endif //BREWPI_BTSCANNER_H 51 | -------------------------------------------------------------------------------- /src/wireless/Inkbird.cpp: -------------------------------------------------------------------------------- 1 | #ifdef HAS_BLUETOOTH 2 | #include 3 | #include "Inkbird.h" 4 | #include "TemperatureFormats.h" 5 | 6 | 7 | void inkbird::update(int16_t temp, uint16_t hum, uint8_t bat, int16_t rssi) 8 | { 9 | rawTemp=temp; 10 | rawHumidity=hum; 11 | battery=bat; 12 | m_lastUpdate = esp_timer_get_time(); 13 | hasData = true; 14 | return; 15 | } 16 | 17 | int16_t inkbird::getTemp() 18 | { 19 | return rawTemp; 20 | } 21 | 22 | uint16_t inkbird::getHumidity() 23 | { 24 | return rawHumidity; 25 | } 26 | 27 | uint8_t inkbird::getBattery() 28 | { 29 | return battery; 30 | } 31 | 32 | bool inkbird::isConnected() 33 | { 34 | return esp_timer_get_time() <= (m_lastUpdate + INKBIRD_CONNECTED_TIMEOUT) && hasData; 35 | } 36 | 37 | long_temperature inkbird::getTempFixedPoint() { 38 | long_temperature intPart = 0; 39 | long_temperature fracPart = 0; 40 | 41 | intPart = (int) rawTemp/100*TEMP_FIXED_POINT_SCALE; 42 | 43 | fracPart = rawTemp % 100; 44 | fracPart = fracPart << TEMP_FIXED_POINT_BITS; // bits for fraction part 45 | 46 | // Since we have two decimals 47 | fracPart = (fracPart + 5) / 10; 48 | fracPart = (fracPart + 5) / 10; 49 | 50 | long_temperature combinedTemp = (intPart) + fracPart + C_OFFSET; 51 | return combinedTemp; 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/wireless/Inkbird.h: -------------------------------------------------------------------------------- 1 | #ifndef BREWPI_INKBIRD_H 2 | #define BREWPI_INKBIRD_H 3 | 4 | #ifdef HAS_BLUETOOTH 5 | 6 | 7 | #include "Brewpi.h" 8 | #include "TempSensor.h" 9 | #include "FastDigitalPin.h" 10 | // #include "Ticks.h" 11 | #include 12 | #include "TemperatureFormats.h" 13 | 14 | 15 | #define INKBIRD_CONNECTED_TIMEOUT (30 * 1000 * 1000) // Time before the sensor is considered "disconnected" (in microseconds) 16 | 17 | class inkbird 18 | { 19 | public: 20 | inkbird(const NimBLEAddress devAddress, int16_t temp, uint16_t hum, uint8_t bat, int16_t rssi) 21 | :deviceAddress(devAddress), m_lastUpdate(esp_timer_get_time()), rawTemp(temp), rawHumidity(hum), battery(bat), hasData(true) {}; 22 | 23 | inkbird(const NimBLEAddress devAddress) 24 | :deviceAddress(devAddress), m_lastUpdate(0), rawTemp(0), rawHumidity(0), battery(0), hasData(false) {}; 25 | 26 | void update(int16_t temp, uint16_t hum, uint8_t bat, int16_t rssi); 27 | int16_t getTemp(); 28 | uint16_t getHumidity(); 29 | uint8_t getBattery(); 30 | long_temperature getTempFixedPoint(); 31 | 32 | bool isConnected(); 33 | 34 | NimBLEAddress deviceAddress; 35 | 36 | uint64_t m_lastUpdate; // Keep track of when we last updated to detect disconnection 37 | 38 | bool operator == (const inkbird& dev) const { return deviceAddress == dev.deviceAddress; } 39 | bool operator != (const inkbird& dev) const { return !operator==(dev); } 40 | 41 | private: 42 | int16_t rawTemp; 43 | uint16_t rawHumidity; 44 | uint8_t battery; 45 | bool hasData; 46 | 47 | }; 48 | 49 | #endif 50 | #endif //BREWPI_INKBIRD_H 51 | -------------------------------------------------------------------------------- /src/wireless/Tilt.cpp: -------------------------------------------------------------------------------- 1 | #ifdef HAS_BLUETOOTH 2 | #include 3 | #include "Tilt.h" 4 | #include "TemperatureFormats.h" 5 | 6 | 7 | void tilt::update(TiltColor color_index, uint16_t temp, uint16_t grav, uint8_t i_tx_pwr, int16_t rssi) 8 | { 9 | if (temp == 999) { // If the temp is 999, the SG actually represents the firmware version of the Tilt. 10 | // version_code = grav; 11 | return; // This also has the (desired) side effect of not logging the 999 "temperature" and 1.00x "gravity" 12 | } else if (grav >= 5000) { // If we received a gravity over 5000 then this Tilt is high resolution (Tilt Pro) 13 | tilt_pro = true; 14 | } else if (grav < 5000) { 15 | tilt_pro = false; 16 | } 17 | 18 | if (i_tx_pwr==197) 19 | m_has_sent_197 = true; 20 | else { 21 | if (m_has_sent_197) 22 | receives_battery = true; 23 | if (receives_battery) 24 | battery_weeks = i_tx_pwr; 25 | } 26 | 27 | rawTemp=temp; 28 | rawGravity=grav; 29 | m_lastUpdate = esp_timer_get_time(); 30 | hasData = true; 31 | color = color_index; 32 | return; 33 | } 34 | 35 | uint16_t tilt::getTemp() 36 | { 37 | return rawTemp; 38 | } 39 | 40 | uint16_t tilt::getGravity() 41 | { 42 | return rawGravity; 43 | } 44 | 45 | bool tilt::isConnected() 46 | { 47 | return esp_timer_get_time() <= (m_lastUpdate + TILT_CONNECTED_TIMEOUT) && hasData; 48 | } 49 | 50 | TiltColor tilt::uuid_to_color_no(std::string uuid) 51 | { 52 | 53 | if (uuid == TILT_COLOR_RED_UUID) 54 | return TiltColor::TILT_COLOR_RED; 55 | else if (uuid == TILT_COLOR_GREEN_UUID) 56 | return TiltColor::TILT_COLOR_GREEN; 57 | else if (uuid == TILT_COLOR_BLACK_UUID) 58 | return TiltColor::TILT_COLOR_BLACK; 59 | else if (uuid == TILT_COLOR_PURPLE_UUID) 60 | return TiltColor::TILT_COLOR_PURPLE; 61 | else if (uuid == TILT_COLOR_ORANGE_UUID) 62 | return TiltColor::TILT_COLOR_ORANGE; 63 | else if (uuid == TILT_COLOR_BLUE_UUID) 64 | return TiltColor::TILT_COLOR_BLUE; 65 | else if (uuid == TILT_COLOR_YELLOW_UUID) 66 | return TiltColor::TILT_COLOR_YELLOW; 67 | else if (uuid == TILT_COLOR_PINK_UUID) 68 | return TiltColor::TILT_COLOR_PINK; 69 | return TiltColor::TILT_COLOR_NONE; // Should never get here 70 | } 71 | 72 | std:: string tilt::get_color_string() { 73 | 74 | switch(color) { 75 | case TiltColor::TILT_COLOR_RED: 76 | return TiltColorNames::red; 77 | case TiltColor::TILT_COLOR_GREEN: 78 | return TiltColorNames::green; 79 | case TiltColor::TILT_COLOR_BLACK: 80 | return TiltColorNames::black; 81 | case TiltColor::TILT_COLOR_PURPLE: 82 | return TiltColorNames::purple; 83 | case TiltColor::TILT_COLOR_ORANGE: 84 | return TiltColorNames::orange; 85 | case TiltColor::TILT_COLOR_BLUE: 86 | return TiltColorNames::red; 87 | case TiltColor::TILT_COLOR_YELLOW: 88 | return TiltColorNames::yellow; 89 | case TiltColor::TILT_COLOR_PINK: 90 | return TiltColorNames::pink; 91 | default: 92 | return TiltColorNames::none; 93 | } 94 | } 95 | 96 | 97 | long_temperature tilt::getTempFixedPoint() { 98 | long_temperature fracPart = 0; 99 | 100 | // Tilts always report in Fahrenheit - convert to celsius and then split 101 | double conv_temp = ((double) rawTemp / (tilt_pro ? 10 : 1) - 32) * 5 / 9; 102 | 103 | // Split into an integer and a fractional part 104 | double intPartRaw; 105 | double fracPartRaw = modf(conv_temp, &intPartRaw); 106 | 107 | // Int part is good to go - just recast it and scale it up 108 | long_temperature intPart = static_cast(intPartRaw) * TEMP_FIXED_POINT_SCALE; 109 | 110 | // Fractional part needs to be scaled up to max precision (0.1deg F, using 0.01deg C instead) 111 | fracPart = static_cast(trunc(fracPartRaw * 100)); 112 | fracPart = fracPart << TEMP_FIXED_POINT_BITS; // bits for fraction part 113 | 114 | // Since we have two decimals 115 | fracPart = (fracPart + 5) / 10; 116 | fracPart = (fracPart + 5) / 10; 117 | 118 | long_temperature combinedTemp = (intPart) + fracPart + C_OFFSET; 119 | return combinedTemp; 120 | } 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /src/wireless/Tilt.h: -------------------------------------------------------------------------------- 1 | #ifndef BREWPI_TILT_H 2 | #define BREWPI_TILT_H 3 | 4 | #ifdef HAS_BLUETOOTH 5 | 6 | 7 | #include "Brewpi.h" 8 | #include "TempSensor.h" 9 | #include "FastDigitalPin.h" 10 | // #include "Ticks.h" 11 | #include 12 | #include "TemperatureFormats.h" 13 | 14 | 15 | #define TILT_COLOR_RED_UUID "a495bb10c5b14b44b5121370f02d74de" 16 | #define TILT_COLOR_GREEN_UUID "a495bb20c5b14b44b5121370f02d74de" 17 | #define TILT_COLOR_BLACK_UUID "a495bb30c5b14b44b5121370f02d74de" 18 | #define TILT_COLOR_PURPLE_UUID "a495bb40c5b14b44b5121370f02d74de" 19 | #define TILT_COLOR_ORANGE_UUID "a495bb50c5b14b44b5121370f02d74de" 20 | #define TILT_COLOR_BLUE_UUID "a495bb60c5b14b44b5121370f02d74de" 21 | #define TILT_COLOR_YELLOW_UUID "a495bb70c5b14b44b5121370f02d74de" 22 | #define TILT_COLOR_PINK_UUID "a495bb80c5b14b44b5121370f02d74de" 23 | 24 | 25 | /** 26 | * \brief Tilt Hydrometer color index 27 | */ 28 | enum TiltColor { 29 | TILT_COLOR_NONE, 30 | TILT_COLOR_RED, 31 | TILT_COLOR_GREEN, 32 | TILT_COLOR_BLACK, 33 | TILT_COLOR_PURPLE, 34 | TILT_COLOR_ORANGE, 35 | TILT_COLOR_BLUE, 36 | TILT_COLOR_YELLOW, 37 | TILT_COLOR_PINK 38 | }; 39 | 40 | 41 | /** 42 | * \brief Tilt Color Names 43 | * \see TiltColor 44 | */ 45 | namespace TiltColorNames { 46 | constexpr auto none = "None"; 47 | constexpr auto red = "Red"; 48 | constexpr auto green = "Green"; 49 | constexpr auto black = "Black"; 50 | constexpr auto purple = "Purple"; 51 | constexpr auto orange = "Orange"; 52 | constexpr auto blue = "Blue"; 53 | constexpr auto yellow = "Yellow"; 54 | constexpr auto pink = "Pink"; 55 | }; 56 | 57 | 58 | #define TILT_CONNECTED_TIMEOUT (90 * 1000 * 1000) // Time before the sensor is considered "disconnected" (in microseconds) 59 | 60 | class tilt 61 | { 62 | public: 63 | // tilt(const NimBLEAddress devAddress, TiltColor color_index, uint16_t temp, uint16_t grav, int16_t rssi) 64 | // :deviceAddress(devAddress), color(color_index), m_lastUpdate(millis()), battery_weeks(0), 65 | // receives_battery(false), tilt_pro(false), rawTemp(temp), rawGravity(grav), hasData(true) {}; 66 | 67 | // tilt(const NimBLEAddress devAddress, TiltColor color_index) 68 | // :deviceAddress(devAddress), color(color_index), m_lastUpdate(0), battery_weeks(0), 69 | // receives_battery(false), tilt_pro(false), rawTemp(0), rawGravity(0), hasData(false) {}; 70 | 71 | tilt(const NimBLEAddress devAddress) 72 | :deviceAddress(devAddress), color(TiltColor::TILT_COLOR_NONE), m_lastUpdate(0), battery_weeks(0), 73 | receives_battery(false), tilt_pro(false), rawTemp(0), rawGravity(0), hasData(false) {}; 74 | 75 | 76 | void update(TiltColor color_index, uint16_t temp, uint16_t grav, uint8_t i_tx_pwr, int16_t rssi); 77 | 78 | std::string get_color_string(); 79 | 80 | 81 | uint16_t getTemp(); 82 | uint16_t getGravity(); 83 | long_temperature getTempFixedPoint(); 84 | bool isConnected(); 85 | static TiltColor uuid_to_color_no(std::string uuid); 86 | 87 | NimBLEAddress deviceAddress; 88 | TiltColor color; 89 | uint64_t m_lastUpdate; // Keep track of when we last updated to detect disconnection 90 | uint8_t battery_weeks; // Weeks since the last battery change (if receives_battery is true) 91 | bool receives_battery; // Tracks if this tilt sends battery life 92 | bool tilt_pro; // Tracks if this tilt is "high resolution" or not (ie. is a Tilt Pro) 93 | 94 | bool operator == (const tilt& dev) const { return (deviceAddress == dev.deviceAddress && color == dev.color); } 95 | bool operator != (const tilt& dev) const { return !operator==(dev); } 96 | 97 | private: 98 | uint16_t rawTemp; 99 | uint16_t rawGravity; 100 | bool hasData; 101 | bool m_has_sent_197; // Used to determine if the tilt sends battery life (a 197 tx_pwr followed by a non-197 tx_pwr) 102 | 103 | }; 104 | 105 | #endif 106 | #endif //BREWPI_TILT_H 107 | --------------------------------------------------------------------------------