├── device ├── rpi │ └── web │ │ ├── __init__.py │ │ ├── charts.py │ │ ├── weatherMicroService.py │ │ └── collector.py └── arduino │ └── SensorReader │ └── SensorReader.ino ├── readme-files ├── cloud.png ├── temperature.png ├── weatherstation1.png └── weatherstation2.png ├── indi-driver ├── docs │ ├── indi.png │ ├── obs.jpeg │ └── INSTALL ├── build.sh ├── cloud-rain-monitor │ ├── indi_cloud_rain_monitor.xml │ ├── cmake_modules │ │ ├── MacroBoolTo01.cmake │ │ ├── FindJPEG.cmake │ │ ├── FindUSB.cmake │ │ ├── MacroOptionalFindPackage.cmake │ │ ├── FindVorbis.cmake │ │ ├── FindFTDI.cmake │ │ ├── FindQHY.cmake │ │ ├── FindASI.cmake │ │ ├── FindQSI.cmake │ │ ├── FindMEADE.cmake │ │ ├── FindSBIG.cmake │ │ ├── FindDC1394.cmake │ │ ├── FindFLI.cmake │ │ ├── FindNova.cmake │ │ ├── FindAPOGEE.cmake │ │ ├── FindMODBUS.cmake │ │ ├── FindFISHCAMP.cmake │ │ ├── FindAIOUSB.cmake │ │ ├── FindCFITSIO.cmake │ │ ├── FindALUT.cmake │ │ ├── FindGPHOTO2.cmake │ │ ├── FindOpenAL.cmake │ │ ├── FindUSB-1.cmake │ │ ├── MacroLogFeature.cmake │ │ └── FindINDI.cmake │ ├── CMakeLists.txt │ ├── cloudrainmonitor.h │ ├── gason.h │ ├── cloudrainmonitor.cpp │ └── gason.cpp └── mock-weather-device.py ├── .idea └── vcs.xml └── README.md /device/rpi/web/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /readme-files/cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokeeffe/cloud-rain-monitor/HEAD/readme-files/cloud.png -------------------------------------------------------------------------------- /indi-driver/docs/indi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokeeffe/cloud-rain-monitor/HEAD/indi-driver/docs/indi.png -------------------------------------------------------------------------------- /indi-driver/docs/obs.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokeeffe/cloud-rain-monitor/HEAD/indi-driver/docs/obs.jpeg -------------------------------------------------------------------------------- /readme-files/temperature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokeeffe/cloud-rain-monitor/HEAD/readme-files/temperature.png -------------------------------------------------------------------------------- /readme-files/weatherstation1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokeeffe/cloud-rain-monitor/HEAD/readme-files/weatherstation1.png -------------------------------------------------------------------------------- /readme-files/weatherstation2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dokeeffe/cloud-rain-monitor/HEAD/readme-files/weatherstation2.png -------------------------------------------------------------------------------- /indi-driver/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | mkdir build 3 | cd build 4 | rm * -rf 5 | cmake -DCMAKE_INSTALL_PREFIX=/usr ../cloud-rain-monitor/ 6 | sudo make install 7 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /indi-driver/docs/INSTALL: -------------------------------------------------------------------------------- 1 | To build and install this indi driver, cd to the same dir as the build.sh script, then sudo ./build.sh 2 | You will need indi dev dependencies installed. Cmake wll inform of any missing deps. 3 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/indi_cloud_rain_monitor.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | indi_cloud_rain_monitor 4 | 1.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /indi-driver/mock-weather-device.py: -------------------------------------------------------------------------------- 1 | # HTTP server to be used for testing 2 | # Run the indi driver and configure to connect to a weather station at http://localhost:8080/weather/true to simulate rain conditions 3 | # 4 | from bottle import route, run, template 5 | 6 | @route('/weather/') 7 | def index(rain): 8 | return template('{"uptime":"05:14:12", "skyTemp": 4.230, "outsideTemp": 1.090, "rain":{{rain}} }', rain=rain) 9 | 10 | run(host='localhost', port=8080) 11 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/MacroBoolTo01.cmake: -------------------------------------------------------------------------------- 1 | # MACRO_BOOL_TO_01( VAR RESULT0 ... RESULTN ) 2 | # This macro evaluates its first argument 3 | # and sets all the given vaiables either to 0 or 1 4 | # depending on the value of the first one 5 | 6 | # Copyright (c) 2006, Alexander Neundorf, 7 | # 8 | # Redistribution and use is allowed according to the terms of the BSD license. 9 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 10 | 11 | 12 | MACRO(MACRO_BOOL_TO_01 FOUND_VAR ) 13 | FOREACH (_current_VAR ${ARGN}) 14 | IF(${FOUND_VAR}) 15 | SET(${_current_VAR} 1) 16 | ELSE(${FOUND_VAR}) 17 | SET(${_current_VAR} 0) 18 | ENDIF(${FOUND_VAR}) 19 | ENDFOREACH(_current_VAR) 20 | ENDMACRO(MACRO_BOOL_TO_01) 21 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.4.7) 2 | PROJECT(indi_cloud_rain_monitor CXX C) 3 | 4 | set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}") 5 | 6 | set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/") 7 | set (VERSION_MAJOR 0) 8 | set (VERSION_MINOR 2) 9 | 10 | find_package(INDI REQUIRED) 11 | 12 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 13 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 14 | include_directories(${INDI_INCLUDE_DIR}) 15 | 16 | ################ Cloud rain monitor ################ 17 | set(cloudrainmonitor_SRCS 18 | ${CMAKE_CURRENT_SOURCE_DIR}/cloudrainmonitor.cpp 19 | ${CMAKE_CURRENT_SOURCE_DIR}/gason.cpp 20 | ) 21 | 22 | add_executable(indi_cloud_rain_monitor ${cloudrainmonitor_SRCS}) 23 | target_link_libraries(indi_cloud_rain_monitor ${INDI_DRIVER_LIBRARIES} curl) 24 | install(TARGETS indi_cloud_rain_monitor RUNTIME DESTINATION bin ) 25 | install(FILES indi_cloud_rain_monitor.xml DESTINATION ${INDI_DATA_DIR}) 26 | 27 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindJPEG.cmake: -------------------------------------------------------------------------------- 1 | # - Find JPEG 2 | # Find the native JPEG includes and library 3 | # This module defines 4 | # JPEG_INCLUDE_DIR, where to find jpeglib.h, etc. 5 | # JPEG_LIBRARIES, the libraries needed to use JPEG. 6 | # JPEG_FOUND, If false, do not try to use JPEG. 7 | # also defined, but not for general use are 8 | # JPEG_LIBRARY, where to find the JPEG library. 9 | 10 | FIND_PATH(JPEG_INCLUDE_DIR jpeglib.h) 11 | 12 | SET(JPEG_NAMES ${JPEG_NAMES} jpeg) 13 | FIND_LIBRARY(JPEG_LIBRARY NAMES ${JPEG_NAMES} ) 14 | 15 | # handle the QUIETLY and REQUIRED arguments and set JPEG_FOUND to TRUE if 16 | # all listed variables are TRUE 17 | INCLUDE(FindPackageHandleStandardArgs) 18 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(JPEG DEFAULT_MSG JPEG_LIBRARY JPEG_INCLUDE_DIR) 19 | 20 | IF(JPEG_FOUND) 21 | SET(JPEG_LIBRARIES ${JPEG_LIBRARY}) 22 | ENDIF(JPEG_FOUND) 23 | 24 | # Deprecated declarations. 25 | SET (NATIVE_JPEG_INCLUDE_PATH ${JPEG_INCLUDE_DIR} ) 26 | GET_FILENAME_COMPONENT (NATIVE_JPEG_LIB_PATH ${JPEG_LIBRARY} PATH) 27 | 28 | MARK_AS_ADVANCED(JPEG_LIBRARY JPEG_INCLUDE_DIR ) 29 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindUSB.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find the USB library 2 | # Once done this defines 3 | # 4 | # LIBUSB_FOUND - system has libusb 5 | # LIBUSB_INCLUDE_DIR - the libusb include directory 6 | # LIBUSB_LIBRARIES - Link these to use libusb 7 | 8 | # Copyright (c) 2006, 2008 Laurent Montel, 9 | # 10 | # Redistribution and use is allowed according to the terms of the BSD license. 11 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 12 | 13 | 14 | if (NOT WIN32) 15 | # use pkg-config to get the directories and then use these values 16 | # in the FIND_PATH() and FIND_LIBRARY() calls 17 | find_package(PkgConfig) 18 | pkg_check_modules(PC_LIBUSB QUIET libusb) 19 | endif(NOT WIN32) 20 | 21 | find_path(LIBUSB_INCLUDE_DIR usb.h 22 | HINTS ${PC_LIBUSB_INCLUDEDIR} ${PC_LIBUSB_INCLUDE_DIRS}) 23 | 24 | find_library(LIBUSB_LIBRARIES NAMES usb 25 | HINTS ${PC_LIBUSB_LIBDIR} ${PC_LIBUSB_LIBRARY_DIRS}) 26 | 27 | include(FindPackageHandleStandardArgs) 28 | find_package_handle_standard_args(LIBUSB DEFAULT_MSG LIBUSB_LIBRARIES LIBUSB_INCLUDE_DIR) 29 | 30 | mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES) 31 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/MacroOptionalFindPackage.cmake: -------------------------------------------------------------------------------- 1 | # - MACRO_OPTIONAL_FIND_PACKAGE() combines FIND_PACKAGE() with an OPTION() 2 | # MACRO_OPTIONAL_FIND_PACKAGE( [QUIT] ) 3 | # This macro is a combination of OPTION() and FIND_PACKAGE(), it 4 | # works like FIND_PACKAGE(), but additionally it automatically creates 5 | # an option name WITH_, which can be disabled via the cmake GUI. 6 | # or via -DWITH_=OFF 7 | # The standard _FOUND variables can be used in the same way 8 | # as when using the normal FIND_PACKAGE() 9 | 10 | # Copyright (c) 2006, Alexander Neundorf, 11 | # 12 | # Redistribution and use is allowed according to the terms of the BSD license. 13 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 14 | 15 | 16 | MACRO (MACRO_OPTIONAL_FIND_PACKAGE _name ) 17 | OPTION(WITH_${_name} "Search for ${_name} package" ON) 18 | if (WITH_${_name}) 19 | FIND_PACKAGE(${_name} ${ARGN}) 20 | else (WITH_${_name}) 21 | set(${_name}_FOUND) 22 | set(${_name}_INCLUDE_DIR) 23 | set(${_name}_INCLUDES) 24 | set(${_name}_LIBRARY) 25 | set(${_name}_LIBRARIES) 26 | endif (WITH_${_name}) 27 | ENDMACRO (MACRO_OPTIONAL_FIND_PACKAGE) 28 | 29 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindVorbis.cmake: -------------------------------------------------------------------------------- 1 | # - Find vorbis 2 | # Find the native vorbis includes and libraries 3 | # 4 | # VORBIS_INCLUDE_DIR - where to find vorbis.h, etc. 5 | # VORBIS_LIBRARIES - List of libraries when using vorbis(file). 6 | # VORBIS_FOUND - True if vorbis found. 7 | 8 | if(VORBIS_INCLUDE_DIR) 9 | # Already in cache, be silent 10 | set(VORBIS_FIND_QUIETLY TRUE) 11 | endif(VORBIS_INCLUDE_DIR) 12 | 13 | find_path(VORBIS_INCLUDE_DIR vorbis/vorbisfile.h) 14 | 15 | find_library(OGG_LIBRARY NAMES ogg) 16 | find_library(VORBIS_LIBRARY NAMES vorbis) 17 | find_library(VORBISFILE_LIBRARY NAMES vorbisfile) 18 | 19 | # Handle the QUIETLY and REQUIRED arguments and set VORBIS_FOUND to TRUE if 20 | # all listed variables are TRUE. 21 | include(FindPackageHandleStandardArgs) 22 | find_package_handle_standard_args(VORBIS DEFAULT_MSG 23 | VORBIS_INCLUDE_DIR OGG_LIBRARY VORBIS_LIBRARY VORBIS_LIBRARY) 24 | 25 | if(VORBIS_FOUND) 26 | set(VORBIS_LIBRARIES ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} ${OGG_LIBRARY}) 27 | else(VORBIS_FOUND) 28 | set(VORBIS_LIBRARIES) 29 | endif(VORBIS_FOUND) 30 | 31 | mark_as_advanced(VORBIS_INCLUDE_DIR) 32 | mark_as_advanced(OGG_LIBRARY VORBIS_LIBRARY VORBISFILE_LIBRARY) 33 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindFTDI.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find FTDI 2 | # Once done this will define 3 | # 4 | # FTDI_FOUND - system has FTDI 5 | # FTDI_INCLUDE_DIR - the FTDI include directory 6 | # FTDI_LIBRARIES - Link these to use FTDI 7 | 8 | # Redistribution and use is allowed according to the terms of the BSD license. 9 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 10 | 11 | if (FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) 12 | 13 | # in cache already 14 | set(FTDI_FOUND TRUE) 15 | message(STATUS "Found libftdi: ${FTDI_LIBRARIES}") 16 | 17 | else (FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) 18 | 19 | find_path(FTDI_INCLUDE_DIR ftdi.h 20 | ${_obIncDir} 21 | ${GNUWIN32_DIR}/include 22 | ) 23 | 24 | find_library(FTDI_LIBRARIES NAMES ftdi 25 | PATHS 26 | ${_obLinkDir} 27 | ${GNUWIN32_DIR}/lib 28 | ) 29 | 30 | if(FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) 31 | set(FTDI_FOUND TRUE) 32 | else (FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) 33 | set(FTDI_FOUND FALSE) 34 | endif(FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) 35 | 36 | 37 | if (FTDI_FOUND) 38 | if (NOT FTDI_FIND_QUIETLY) 39 | message(STATUS "Found FTDI: ${FTDI_LIBRARIES}") 40 | endif (NOT FTDI_FIND_QUIETLY) 41 | else (FTDI_FOUND) 42 | if (FTDI_FIND_REQUIRED) 43 | message(FATAL_ERROR "FTDI not found. Please install libftdi-dev") 44 | endif (FTDI_FIND_REQUIRED) 45 | endif (FTDI_FOUND) 46 | 47 | mark_as_advanced(FTDI_INCLUDE_DIR FTDI_LIBRARIES) 48 | 49 | endif (FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) 50 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindQHY.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find QHY Library 2 | # Once done this will define 3 | # 4 | # QHY_FOUND - system has QHY 5 | # QHY_INCLUDE_DIR - the QHY include directory 6 | # QHY_LIBRARIES - Link these to use QHY 7 | 8 | # Redistribution and use is allowed according to the terms of the BSD license. 9 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 10 | 11 | if (QHY_INCLUDE_DIR AND QHY_LIBRARIES) 12 | 13 | # in cache already 14 | set(QHY_FOUND TRUE) 15 | message(STATUS "Found libqhy: ${QHY_LIBRARIES}") 16 | 17 | else (QHY_INCLUDE_DIR AND QHY_LIBRARIES) 18 | 19 | find_path(QHY_INCLUDE_DIR qhyccd.h 20 | PATH_SUFFIXES libqhy 21 | ${_obIncDir} 22 | ${GNUWIN32_DIR}/include 23 | ) 24 | 25 | find_library(QHY_LIBRARIES NAMES qhy 26 | PATHS 27 | ${_obLinkDir} 28 | ${GNUWIN32_DIR}/lib 29 | ) 30 | 31 | if(QHY_INCLUDE_DIR AND QHY_LIBRARIES) 32 | set(QHY_FOUND TRUE) 33 | else (QHY_INCLUDE_DIR AND QHY_LIBRARIES) 34 | set(QHY_FOUND FALSE) 35 | endif(QHY_INCLUDE_DIR AND QHY_LIBRARIES) 36 | 37 | 38 | if (QHY_FOUND) 39 | if (NOT QHY_FIND_QUIETLY) 40 | message(STATUS "Found QHY: ${QHY_LIBRARIES}") 41 | endif (NOT QHY_FIND_QUIETLY) 42 | else (QHY_FOUND) 43 | if (QHY_FIND_REQUIRED) 44 | message(FATAL_ERROR "QHY not found. Please install libqhy http://www.indilib.org") 45 | endif (QHY_FIND_REQUIRED) 46 | endif (QHY_FOUND) 47 | 48 | mark_as_advanced(QHY_INCLUDE_DIR QHY_LIBRARIES) 49 | 50 | endif (QHY_INCLUDE_DIR AND QHY_LIBRARIES) 51 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindASI.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find ASI Library 2 | # Once done this will define 3 | # 4 | # ASI_FOUND - system has ASI 5 | # ASI_INCLUDE_DIR - the ASI include directory 6 | # ASI_LIBRARIES - Link these to use ASI 7 | 8 | # Redistribution and use is allowed according to the terms of the BSD license. 9 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 10 | 11 | if (ASI_INCLUDE_DIR AND ASI_LIBRARIES) 12 | 13 | # in cache already 14 | set(ASI_FOUND TRUE) 15 | message(STATUS "Found libasi: ${ASI_LIBRARIES}") 16 | 17 | else (ASI_INCLUDE_DIR AND ASI_LIBRARIES) 18 | 19 | find_path(ASI_INCLUDE_DIR ASICamera2.h 20 | PATH_SUFFIXES libasi 21 | ${_obIncDir} 22 | ${GNUWIN32_DIR}/include 23 | ) 24 | 25 | find_library(ASI_LIBRARIES NAMES ASICamera2 26 | PATHS 27 | ${_obLinkDir} 28 | ${GNUWIN32_DIR}/lib 29 | ) 30 | 31 | if(ASI_INCLUDE_DIR AND ASI_LIBRARIES) 32 | set(ASI_FOUND TRUE) 33 | else (ASI_INCLUDE_DIR AND ASI_LIBRARIES) 34 | set(ASI_FOUND FALSE) 35 | endif(ASI_INCLUDE_DIR AND ASI_LIBRARIES) 36 | 37 | 38 | if (ASI_FOUND) 39 | if (NOT ASI_FIND_QUIETLY) 40 | message(STATUS "Found ASI: ${ASI_LIBRARIES}") 41 | endif (NOT ASI_FIND_QUIETLY) 42 | else (ASI_FOUND) 43 | if (ASI_FIND_REQUIRED) 44 | message(FATAL_ERROR "ASI not found. Please install libasi http://www.indilib.org") 45 | endif (ASI_FIND_REQUIRED) 46 | endif (ASI_FOUND) 47 | 48 | mark_as_advanced(ASI_INCLUDE_DIR ASI_LIBRARIES) 49 | 50 | endif (ASI_INCLUDE_DIR AND ASI_LIBRARIES) 51 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindQSI.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find Quantum Scientific Imaging Library 2 | # Once done this will define 3 | # 4 | # QSI_FOUND - system has QSI 5 | # QSI_INCLUDE_DIR - the QSI include directory 6 | # QSI_LIBRARIES - Link these to use QSI 7 | 8 | # Redistribution and use is allowed according to the terms of the BSD license. 9 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 10 | 11 | if (QSI_INCLUDE_DIR AND QSI_LIBRARIES) 12 | 13 | # in cache already 14 | set(QSI_FOUND TRUE) 15 | message(STATUS "Found libqsiapi: ${QSI_LIBRARIES}") 16 | 17 | else (QSI_INCLUDE_DIR AND QSI_LIBRARIES) 18 | 19 | find_path(QSI_INCLUDE_DIR qsiapi.h 20 | PATH_SUFFIXES qsiapi 21 | ${_obIncDir} 22 | ${GNUWIN32_DIR}/include 23 | ) 24 | 25 | find_library(QSI_LIBRARIES NAMES qsiapi 26 | PATHS 27 | ${_obLinkDir} 28 | ${GNUWIN32_DIR}/lib 29 | ) 30 | 31 | if(QSI_INCLUDE_DIR AND QSI_LIBRARIES) 32 | set(QSI_FOUND TRUE) 33 | else (QSI_INCLUDE_DIR AND QSI_LIBRARIES) 34 | set(QSI_FOUND FALSE) 35 | endif(QSI_INCLUDE_DIR AND QSI_LIBRARIES) 36 | 37 | 38 | if (QSI_FOUND) 39 | if (NOT QSI_FIND_QUIETLY) 40 | message(STATUS "Found QSI: ${QSI_LIBRARIES}") 41 | endif (NOT QSI_FIND_QUIETLY) 42 | else (QSI_FOUND) 43 | if (QSI_FIND_REQUIRED) 44 | message(FATAL_ERROR "QSI not found. Please install libqsi http://www.indilib.org") 45 | endif (QSI_FIND_REQUIRED) 46 | endif (QSI_FOUND) 47 | 48 | mark_as_advanced(QSI_INCLUDE_DIR QSI_LIBRARIES) 49 | 50 | endif (QSI_INCLUDE_DIR AND QSI_LIBRARIES) 51 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindMEADE.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find Meade DSI Library. 2 | # Once done this will define 3 | # 4 | # MEADEDSI_FOUND - system has Meade DSI 5 | # MEADEDSI_LIBRARIES - Link these to use Meade DSI 6 | 7 | # Copyright (c) 2006, Jasem Mutlaq 8 | # Based on FindLibfacile by Carsten Niehaus, 9 | # 10 | # Redistribution and use is allowed according to the terms of the BSD license. 11 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 12 | 13 | if (MEADEDSI_LIBRARIES) 14 | 15 | # in cache already 16 | set(MEADEDSI_FOUND TRUE) 17 | message(STATUS "Found MEADEDSI: ${MEADEDSI_LIBRARIES}") 18 | 19 | else (MEADEDSI_LIBRARIES) 20 | 21 | find_library(MEADEDSI_LIBRARIES NAMES dsi 22 | PATHS 23 | ${_obLinkDir} 24 | ${GNUWIN32_DIR}/lib 25 | ) 26 | 27 | set(CMAKE_REQUIRED_LIBRARIES ${MEADEDSI_LIBRARIES}) 28 | 29 | if(MEADEDSI_LIBRARIES) 30 | set(MEADEDSI_FOUND TRUE) 31 | else (MEADEDSI_LIBRARIES) 32 | set(MEADEDSI_FOUND FALSE) 33 | endif(MEADEDSI_LIBRARIES) 34 | 35 | if (MEADEDSI_FOUND) 36 | if (NOT MEADEDSI_FIND_QUIETLY) 37 | message(STATUS "Found Meade DSI: ${MEADEDSI_LIBRARIES}") 38 | endif (NOT MEADEDSI_FIND_QUIETLY) 39 | else (MEADEDSI_FOUND) 40 | if (MEADEDSI_FIND_REQUIRED) 41 | message(FATAL_ERROR "Meade DSI not found. Please install Meade DSI library. http://linuxdsi.sourceforge.net") 42 | endif (MEADEDSI_FIND_REQUIRED) 43 | endif (MEADEDSI_FOUND) 44 | 45 | mark_as_advanced(MEADEDSI_LIBRARIES) 46 | 47 | endif (MEADEDSI_LIBRARIES) 48 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindSBIG.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find SBIG Universal Library 2 | # Once done this will define 3 | # 4 | # SBIG_FOUND - system has SBIG 5 | # SBIG_INCLUDE_DIR - the SBIG include directory 6 | # SBIG_LIBRARIES - Link these to use SBIG 7 | 8 | # Redistribution and use is allowed according to the terms of the BSD license. 9 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 10 | 11 | if (SBIG_INCLUDE_DIR AND SBIG_LIBRARIES) 12 | 13 | # in cache already 14 | set(SBIG_FOUND TRUE) 15 | message(STATUS "Found libsbig: ${SBIG_LIBRARIES}") 16 | 17 | else (SBIG_INCLUDE_DIR AND SBIG_LIBRARIES) 18 | 19 | find_path(SBIG_INCLUDE_DIR sbigudrv.h 20 | PATH_SUFFIXES libsbig 21 | ${_obIncDir} 22 | ${GNUWIN32_DIR}/include 23 | ) 24 | 25 | find_library(SBIG_LIBRARIES NAMES sbigudrv 26 | PATHS 27 | ${_obLinkDir} 28 | ${GNUWIN32_DIR}/lib 29 | ) 30 | 31 | if(SBIG_INCLUDE_DIR AND SBIG_LIBRARIES) 32 | set(SBIG_FOUND TRUE) 33 | else (SBIG_INCLUDE_DIR AND SBIG_LIBRARIES) 34 | set(SBIG_FOUND FALSE) 35 | endif(SBIG_INCLUDE_DIR AND SBIG_LIBRARIES) 36 | 37 | 38 | if (SBIG_FOUND) 39 | if (NOT SBIG_FIND_QUIETLY) 40 | message(STATUS "Found SBIG: ${SBIG_LIBRARIES}") 41 | endif (NOT SBIG_FIND_QUIETLY) 42 | else (SBIG_FOUND) 43 | if (SBIG_FIND_REQUIRED) 44 | message(FATAL_ERROR "SBIG not found. Please install SBIG Library http://www.indilib.org") 45 | endif (SBIG_FIND_REQUIRED) 46 | endif (SBIG_FOUND) 47 | 48 | mark_as_advanced(SBIG_INCLUDE_DIR SBIG_LIBRARIES) 49 | 50 | endif (SBIG_INCLUDE_DIR AND SBIG_LIBRARIES) 51 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindDC1394.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find dc1394 library (version 2) and include files 2 | # Once done this will define 3 | # 4 | # DC1394_FOUND - system has DC1394 5 | # DC1394_INCLUDE_DIR - the DC1394 include directory 6 | # DC1394_LIBRARIES - Link these to use DC1394 7 | 8 | # Redistribution and use is allowed according to the terms of the BSD license. 9 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 10 | 11 | if (DC1394_INCLUDE_DIR AND DC1394_LIBRARIES) 12 | 13 | # in cache already 14 | set(DC1394_FOUND TRUE) 15 | message(STATUS "Found libdc1394: ${DC1394_LIBRARIES}") 16 | 17 | else (DC1394_INCLUDE_DIR AND DC1394_LIBRARIES) 18 | 19 | find_path(DC1394_INCLUDE_DIR control.h 20 | PATH_SUFFIXES dc1394 21 | ${_obIncDir} 22 | ${GNUWIN32_DIR}/include 23 | ) 24 | 25 | find_library(DC1394_LIBRARIES NAMES dc1394 26 | PATHS 27 | ${_obLinkDir} 28 | ${GNUWIN32_DIR}/lib 29 | ) 30 | 31 | if(DC1394_INCLUDE_DIR AND DC1394_LIBRARIES) 32 | set(DC1394_FOUND TRUE) 33 | else (DC1394_INCLUDE_DIR AND DC1394_LIBRARIES) 34 | set(DC1394_FOUND FALSE) 35 | endif(DC1394_INCLUDE_DIR AND DC1394_LIBRARIES) 36 | 37 | 38 | if (DC1394_FOUND) 39 | if (NOT DC1394_FIND_QUIETLY) 40 | message(STATUS "Found DC1394: ${DC1394_LIBRARIES}") 41 | endif (NOT DC1394_FIND_QUIETLY) 42 | else (DC1394_FOUND) 43 | if (DC1394_FIND_REQUIRED) 44 | message(FATAL_ERROR "DC1394 not found. Please install libdc1395") 45 | endif (DC1394_FIND_REQUIRED) 46 | endif (DC1394_FOUND) 47 | 48 | mark_as_advanced(DC1394_INCLUDE_DIR DC1394_LIBRARIES) 49 | 50 | endif (DC1394_INCLUDE_DIR AND DC1394_LIBRARIES) 51 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindFLI.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find Finger Lakes Instruments Library 2 | # Once done this will define 3 | # 4 | # FLI_FOUND - system has FLI 5 | # FLI_INCLUDE_DIR - the FLI include directory 6 | # FLI_LIBRARIES - Link these to use FLI 7 | 8 | # Copyright (c) 2008, Jasem Mutlaq 9 | # Based on FindLibfacile by Carsten Niehaus, 10 | # 11 | # Redistribution and use is allowed according to the terms of the BSD license. 12 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 13 | 14 | if (FLI_INCLUDE_DIR AND FLI_LIBRARIES) 15 | 16 | # in cache already 17 | set(FLI_FOUND TRUE) 18 | message(STATUS "Found libfli: ${FLI_LIBRARIES}") 19 | 20 | else (FLI_INCLUDE_DIR AND FLI_LIBRARIES) 21 | 22 | find_path(FLI_INCLUDE_DIR libfli.h 23 | PATH_SUFFIXES fli 24 | ${_obIncDir} 25 | ${GNUWIN32_DIR}/include 26 | ) 27 | 28 | find_library(FLI_LIBRARIES NAMES fli 29 | PATHS 30 | ${_obLinkDir} 31 | ${GNUWIN32_DIR}/lib 32 | ) 33 | 34 | if(FLI_INCLUDE_DIR AND FLI_LIBRARIES) 35 | set(FLI_FOUND TRUE) 36 | else (FLI_INCLUDE_DIR AND FLI_LIBRARIES) 37 | set(FLI_FOUND FALSE) 38 | endif(FLI_INCLUDE_DIR AND FLI_LIBRARIES) 39 | 40 | 41 | if (FLI_FOUND) 42 | if (NOT FLI_FIND_QUIETLY) 43 | message(STATUS "Found FLI: ${FLI_LIBRARIES}") 44 | endif (NOT FLI_FIND_QUIETLY) 45 | else (FLI_FOUND) 46 | if (FLI_FIND_REQUIRED) 47 | message(FATAL_ERROR "FLI not found. Please install libfli-dev. http://www.indilib.org") 48 | endif (FLI_FIND_REQUIRED) 49 | endif (FLI_FOUND) 50 | 51 | mark_as_advanced(FLI_INCLUDE_DIR FLI_LIBRARIES) 52 | 53 | endif (FLI_INCLUDE_DIR AND FLI_LIBRARIES) 54 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindNova.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find NOVA 2 | # Once done this will define 3 | # 4 | # NOVA_FOUND - system has NOVA 5 | # NOVA_INCLUDE_DIR - the NOVA include directory 6 | # NOVA_LIBRARIES - Link these to use NOVA 7 | 8 | # Copyright (c) 2006, Jasem Mutlaq 9 | # Based on FindLibfacile by Carsten Niehaus, 10 | # 11 | # Redistribution and use is allowed according to the terms of the BSD license. 12 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 13 | 14 | if (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) 15 | 16 | # in cache already 17 | set(NOVA_FOUND TRUE) 18 | message(STATUS "Found libnova: ${NOVA_LIBRARIES}") 19 | 20 | else (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) 21 | 22 | find_path(NOVA_INCLUDE_DIR libnova.h 23 | PATH_SUFFIXES libnova 24 | ${_obIncDir} 25 | ${GNUWIN32_DIR}/include 26 | ) 27 | 28 | find_library(NOVA_LIBRARIES NAMES nova 29 | PATHS 30 | ${_obLinkDir} 31 | ${GNUWIN32_DIR}/lib 32 | ) 33 | 34 | set(CMAKE_REQUIRED_INCLUDES ${NOVA_INCLUDE_DIR}) 35 | set(CMAKE_REQUIRED_LIBRARIES ${NOVA_LIBRARIES}) 36 | 37 | if(NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) 38 | set(NOVA_FOUND TRUE) 39 | else (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) 40 | set(NOVA_FOUND FALSE) 41 | endif(NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) 42 | 43 | if (NOVA_FOUND) 44 | if (NOT Nova_FIND_QUIETLY) 45 | message(STATUS "Found NOVA: ${NOVA_LIBRARIES}") 46 | endif (NOT Nova_FIND_QUIETLY) 47 | else (NOVA_FOUND) 48 | if (Nova_FIND_REQUIRED) 49 | message(FATAL_ERROR "libnova not found. Please install libnova0-devel. http://indi.sf.net") 50 | endif (Nova_FIND_REQUIRED) 51 | endif (NOVA_FOUND) 52 | 53 | mark_as_advanced(NOVA_INCLUDE_DIR NOVA_LIBRARIES) 54 | 55 | endif (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) 56 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindAPOGEE.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find Apogee Instruments Library 2 | # Once done this will define 3 | # 4 | # APOGEE_FOUND - system has APOGEE 5 | # APOGEE_INCLUDE_DIR - the APOGEE include directory 6 | # APOGEE_LIBRARY - Link these to use APOGEE 7 | 8 | # Copyright (c) 2008, Jasem Mutlaq 9 | # Based on FindLibfacile by Carsten Niehaus, 10 | # 11 | # Redistribution and use is allowed according to the terms of the BSD license. 12 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 13 | 14 | if (APOGEE_INCLUDE_DIR AND APOGEE_LIBRARY) 15 | 16 | # in cache already 17 | set(APOGEE_FOUND TRUE) 18 | message(STATUS "Found libapogee: ${APOGEE_LIBRARY}") 19 | 20 | else (APOGEE_INCLUDE_DIR AND APOGEE_LIBRARY) 21 | 22 | find_path(APOGEE_INCLUDE_DIR ApogeeCam.h 23 | PATH_SUFFIXES libapogee 24 | ${_obIncDir} 25 | ${GNUWIN32_DIR}/include 26 | ) 27 | 28 | # Find Apogee Library 29 | find_library(APOGEE_LIBRARY NAMES apogee 30 | PATHS 31 | ${_obLinkDir} 32 | ${GNUWIN32_DIR}/lib 33 | ) 34 | 35 | if(APOGEE_INCLUDE_DIR AND APOGEE_LIBRARY) 36 | set(APOGEE_FOUND TRUE) 37 | else (APOGEE_INCLUDE_DIR AND APOGEE_LIBRARY) 38 | set(APOGEE_FOUND FALSE) 39 | endif(APOGEE_INCLUDE_DIR AND APOGEE_LIBRARY) 40 | 41 | if (APOGEE_FOUND) 42 | if (NOT APOGEE_FIND_QUIETLY) 43 | message(STATUS "Found APOGEE: ${APOGEE_LIBRARY}") 44 | endif (NOT APOGEE_FIND_QUIETLY) 45 | else (APOGEE_FOUND) 46 | if (APOGEE_FIND_REQUIRED) 47 | message(FATAL_ERROR "libapogee not found. Cannot compile Apogee CCD Driver. Please install libapogee and try again. http://www.indilib.org") 48 | endif (APOGEE_FIND_REQUIRED) 49 | endif (APOGEE_FOUND) 50 | 51 | mark_as_advanced(APOGEE_INCLUDE_DIR APOGEE_LIBRARY) 52 | 53 | endif (APOGEE_INCLUDE_DIR AND APOGEE_LIBRARY) 54 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindMODBUS.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find libmodbus 2 | # Once done this will define 3 | # 4 | # MODBUS_FOUND - system has MODBUS 5 | # MODBUS_INCLUDE_DIR - the MODBUS include directory 6 | # MODBUS_LIBRARIES - Link these to use MODBUS 7 | 8 | # Copyright (c) 2006, Jasem Mutlaq 9 | # Based on FindLibfacile by Carsten Niehaus, 10 | # 11 | # Redistribution and use is allowed according to the terms of the BSD license. 12 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 13 | 14 | if (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) 15 | 16 | # in cache already 17 | set(MODBUS_FOUND TRUE) 18 | message(STATUS "Found libmodbus: ${MODBUS_LIBRARIES}") 19 | 20 | else (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) 21 | 22 | find_path(MODBUS_INCLUDE_DIR modbus.h 23 | PATH_SUFFIXES modbus 24 | ${_obIncDir} 25 | ${GNUWIN32_DIR}/include 26 | ) 27 | 28 | find_library(MODBUS_LIBRARIES NAMES modbus 29 | PATHS 30 | ${_obLinkDir} 31 | ${GNUWIN32_DIR}/lib 32 | ) 33 | 34 | set(CMAKE_REQUIRED_INCLUDES ${MODBUS_INCLUDE_DIR}) 35 | set(CMAKE_REQUIRED_LIBRARIES ${MODBUS_LIBRARIES}) 36 | 37 | if(MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) 38 | set(MODBUS_FOUND TRUE) 39 | else (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) 40 | set(MODBUS_FOUND FALSE) 41 | endif(MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) 42 | 43 | if (MODBUS_FOUND) 44 | if (NOT MODBUS_FIND_QUIETLY) 45 | message(STATUS "Found libmodbus: ${MODBUS_LIBRARIES}") 46 | endif (NOT MODBUS_FIND_QUIETLY) 47 | else (MODBUS_FOUND) 48 | if (MODBUS_FIND_REQUIRED) 49 | message(FATAL_ERROR "libmodbus not found. Please install libmodbus-devel. https://launchpad.net/libmodbus/") 50 | endif (MODBUS_FIND_REQUIRED) 51 | endif (MODBUS_FOUND) 52 | 53 | mark_as_advanced(MODBUS_INCLUDE_DIR MODBUS_LIBRARIES) 54 | 55 | endif (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) 56 | 57 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindFISHCAMP.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find FISHCAMP CCD 2 | # Once done this will define 3 | # 4 | # FISHCAMP_FOUND - system has FISHCAMP 5 | # FISHCAMP_LIBRARIES - Link these to use FISHCAMP 6 | # FISHCAMP_INCLUDE_DIR - Fishcamp include directory 7 | 8 | # Copyright (c) 2006, Jasem Mutlaq 9 | # Based on FindLibfacile by Carsten Niehaus, 10 | # 11 | # Redistribution and use is allowed according to the terms of the BSD license. 12 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 13 | 14 | if (FISHCAMP_LIBRARIES AND FISHCAMP_INCLUDE_DIR) 15 | 16 | # in cache already 17 | set(FISHCAMP_FOUND TRUE) 18 | message(STATUS "Found FISHCAMP: ${FISHCAMP_LIBRARIES}") 19 | 20 | else (FISHCAMP_LIBRARIES AND FISHCAMP_INCLUDE_DIR) 21 | 22 | find_library(FISHCAMP_LIBRARIES NAMES fishcamp 23 | PATHS 24 | ${_obLinkDir} 25 | ${GNUWIN32_DIR}/lib 26 | ) 27 | 28 | find_path(FISHCAMP_INCLUDE_DIR fishcamp.h 29 | PATH_SUFFIXES libfishcamp 30 | ${_obIncDir} 31 | ${GNUWIN32_DIR}/include 32 | ) 33 | 34 | set(CMAKE_REQUIRED_LIBRARIES ${FISHCAMP_LIBRARIES}) 35 | 36 | if(FISHCAMP_LIBRARIES AND FISHCAMP_INCLUDE_DIR) 37 | set(FISHCAMP_FOUND TRUE) 38 | else (FISHCAMP_LIBRARIES AND FISHCAMP_INCLUDE_DIR) 39 | set(FISHCAMP_FOUND FALSE) 40 | endif(FISHCAMP_LIBRARIES AND FISHCAMP_INCLUDE_DIR) 41 | 42 | if (FISHCAMP_FOUND) 43 | if (NOT FISHCAMP_FIND_QUIETLY) 44 | message(STATUS "Found FISHCAMP: ${FISHCAMP_LIBRARIES}") 45 | endif (NOT FISHCAMP_FIND_QUIETLY) 46 | else (FISHCAMP_FOUND) 47 | if (FISHCAMP_FIND_REQUIRED) 48 | message(FATAL_ERROR "FISHCAMP not found. Please install FISHCAMP library. http://www.indilib.org") 49 | endif (FISHCAMP_FIND_REQUIRED) 50 | endif (FISHCAMP_FOUND) 51 | 52 | mark_as_advanced(FISHCAMP_LIBRARIES FISHCAMP_INCLUDE_DIR) 53 | 54 | endif (FISHCAMP_LIBRARIES AND FISHCAMP_INCLUDE_DIR) 55 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cloudrainmonitor.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Copyright(c) 2016 Derek OKeeffe. All rights reserved. 3 | 4 | INDI driver for a Cloud and rain monitor for an astronomical observatory 5 | 6 | This program is free software; you can redistribute it and/or modify it 7 | under the terms of the GNU General Public License as published by the Free 8 | Software Foundation; either version 2 of the License, or (at your option) 9 | any later version. 10 | 11 | This program is distributed in the hope that it will be useful, but WITHOUT 12 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 | more details. 15 | 16 | You should have received a copy of the GNU Library General Public License 17 | along with this library; see the file COPYING.LIB. If not, write to 18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 | Boston, MA 02110-1301, USA. 20 | 21 | The full GNU General Public License is included in this distribution in the 22 | file called LICENSE. 23 | *******************************************************************************/ 24 | 25 | #ifndef INDI_CLOUDRAINMONITOR_H 26 | #define INDI_CLOUDRAINMONITOR_H 27 | 28 | #include "indiweather.h" 29 | 30 | class IndiCloudRainMonitor : public INDI::Weather 31 | { 32 | public: 33 | IndiCloudRainMonitor(); 34 | virtual ~IndiCloudRainMonitor(); 35 | 36 | // Generic indi device entries 37 | bool Connect(); 38 | bool Disconnect(); 39 | const char *getDefaultName(); 40 | 41 | virtual bool initProperties(); 42 | virtual void ISGetProperties (const char *dev); 43 | virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); 44 | 45 | protected: 46 | virtual IPState updateWeather(); 47 | virtual bool saveConfigItems(FILE *fp); 48 | 49 | private: 50 | IText httpEndpointT[1]; 51 | ITextVectorProperty httpEndpointTP; 52 | 53 | }; 54 | 55 | #endif // INDI_CLOUDRAINMONITOR_H 56 | -------------------------------------------------------------------------------- /device/arduino/SensorReader/SensorReader.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Arduino firmware for a basic weather station for an astronomical observatory. 3 | * Sends sensor readings from a MLX90614 IR sensor and a rain sensor. 4 | * Sends firmata messages as json strings once per second. 5 | * 6 | * Uses Adafruit's Adafruit_MLX90614 library and wiring, see https://learn.adafruit.com/using-melexis-mlx90614-non-contact-sensors/wiring-and-test 7 | * 8 | * PARTS: 9 | * 1 x Arduino nano (http://www.dx.com/p/arduino-nano-v3-0-81877#.ViKE2RCrRE4) 10 | * 1 x RG-11 Rain sensor 11 | * 1 x MLX90614 IR temp sensor 12 | * 13 | * Wiring: 14 | * Rain sensor: 15 | * Relay is attached to pin 8 and acts as a simple on off switch. Ensure you wire with a pull-down resistor. If you dont know what that means goodle 'arduino button' to see how a basic switch/button is wired. 16 | * MLX90614 17 | * Wired to A4 and A5 with 2 pull up resistors (see https://learn.adafruit.com/using-melexis-mlx90614-non-contact-sensors/wiring-and-test) 18 | * 19 | * Sample json message 20 | * {"rain":false,"sky":20.93,"ambient":21.93} 21 | * 22 | */ 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #define RAIN_SENSOR_PIN 8 29 | 30 | Adafruit_MLX90614 mlx = Adafruit_MLX90614(); 31 | 32 | /** 33 | * Startup firmata and the mlx 34 | */ 35 | void setup() { 36 | Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); 37 | Firmata.begin(57600); 38 | pinMode(8,INPUT); 39 | mlx.begin(); 40 | } 41 | 42 | /** 43 | * Once per second take readings from sensors, build a json string and send over firmata. 44 | */ 45 | void loop() 46 | { 47 | char charBuf[50]; 48 | String message = "{\"rain\":"; 49 | if(digitalRead(RAIN_SENSOR_PIN)==HIGH) { 50 | message += "true,"; 51 | } else { 52 | message += "false,"; 53 | } 54 | message += "\"sky\":"; 55 | message += mlx.readObjectTempC(); 56 | message += ",\"ambient\":"; 57 | message += mlx.readAmbientTempC(); 58 | message += "}"; 59 | message.toCharArray(charBuf, 50); 60 | Firmata.sendString(charBuf); 61 | delay(1000); 62 | } 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindAIOUSB.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find libaiousb 2 | # Once done this will define 3 | # 4 | # AIOUSB_FOUND - system has AIOUSB 5 | # AIOUSB_INCLUDE_DIR - the AIOUSB include directory 6 | # AIOUSB_LIBRARIES - Link these to use AIOUSB (C) 7 | # AIOUSB_CPP_LIBRARIES - Link these to use AIOUSB (C++) 8 | 9 | # Copyright (c) 2006, Jasem Mutlaq 10 | # Based on FindLibfacile by Carsten Niehaus, 11 | # 12 | # Redistribution and use is allowed according to the terms of the BSD license. 13 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 14 | 15 | if (AIOUSB_INCLUDE_DIR AND AIOUSB_LIBRARIES AND AIOUSB_CPP_LIBRARIES) 16 | 17 | # in cache already 18 | set(AIOUSB_FOUND TRUE) 19 | message(STATUS "Found libaiusb: ${AIOUSB_LIBRARIES}") 20 | message(STATUS "Found libaiusbcpp: ${AIOUSB_CPP_LIBRARIES}") 21 | 22 | else (AIOUSB_INCLUDE_DIR AND AIOUSB_LIBRARIES AND AIOUSB_CPP_LIBRARIES) 23 | 24 | find_path(AIOUSB_INCLUDE_DIR aiousb.h 25 | ${_obIncDir} 26 | ${GNUWIN32_DIR}/include 27 | ) 28 | 29 | find_library(AIOUSB_LIBRARIES NAMES aiousb 30 | PATHS 31 | ${_obLinkDir} 32 | ${GNUWIN32_DIR}/lib 33 | ) 34 | 35 | find_library(AIOUSB_CPP_LIBRARIES NAMES aiousbcpp 36 | PATHS 37 | ${_obLinkDir} 38 | ${GNUWIN32_DIR}/lib 39 | ) 40 | 41 | if(AIOUSB_INCLUDE_DIR AND AIOUSB_LIBRARIES AND AIOUSB_CPP_LIBRARIES) 42 | set(AIOUSB_FOUND TRUE) 43 | else (AIOUSB_INCLUDE_DIR AND AIOUSB_LIBRARIES AND AIOUSB_CPP_LIBRARIES) 44 | set(AIOUSB_FOUND FALSE) 45 | endif(AIOUSB_INCLUDE_DIR AND AIOUSB_LIBRARIES AND AIOUSB_CPP_LIBRARIES) 46 | 47 | if (AIOUSB_FOUND) 48 | if (NOT AIOUSB_FIND_QUIETLY) 49 | message(STATUS "Found libaiousb: ${AIOUSB_LIBRARIES}") 50 | message(STATUS "Found libaiusbcpp: ${AIOUSB_CPP_LIBRARIES}") 51 | endif (NOT AIOUSB_FIND_QUIETLY) 52 | else (AIOUSB_FOUND) 53 | if (AIOUSB_FIND_REQUIRED) 54 | message(FATAL_ERROR "libaiousb not found. Please install libaiousb. https://www.accesio.com") 55 | endif (AIOUSB_FIND_REQUIRED) 56 | endif (AIOUSB_FOUND) 57 | 58 | mark_as_advanced(AIOUSB_INCLUDE_DIR AIOUSB_LIBRARIES AIOUSB_CPP_LIBRARIES) 59 | 60 | endif (AIOUSB_INCLUDE_DIR AND AIOUSB_LIBRARIES AND AIOUSB_CPP_LIBRARIES) 61 | 62 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindCFITSIO.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find CFITSIO 2 | # Once done this will define 3 | # 4 | # CFITSIO_FOUND - system has CFITSIO 5 | # CFITSIO_INCLUDE_DIR - the CFITSIO include directory 6 | # CFITSIO_LIBRARIES - Link these to use CFITSIO 7 | # CFITSIO_VERSION_STRING - Human readable version number of cfitsio 8 | # CFITSIO_VERSION_MAJOR - Major version number of cfitsio 9 | # CFITSIO_VERSION_MINOR - Minor version number of cfitsio 10 | 11 | # Copyright (c) 2006, Jasem Mutlaq 12 | # Based on FindLibfacile by Carsten Niehaus, 13 | # 14 | # Redistribution and use is allowed according to the terms of the BSD license. 15 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 16 | 17 | if (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) 18 | 19 | # in cache already 20 | set(CFITSIO_FOUND TRUE) 21 | message(STATUS "Found CFITSIO: ${CFITSIO_LIBRARIES}") 22 | 23 | 24 | else (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) 25 | 26 | # JM: Packages from different distributions have different suffixes 27 | find_path(CFITSIO_INCLUDE_DIR fitsio.h 28 | PATH_SUFFIXES libcfitsio3 libcfitsio0 cfitsio 29 | ${_obIncDir} 30 | ${GNUWIN32_DIR}/include 31 | ) 32 | 33 | find_library(CFITSIO_LIBRARIES NAMES cfitsio 34 | PATHS 35 | ${_obLinkDir} 36 | ${GNUWIN32_DIR}/lib 37 | ) 38 | 39 | if(CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) 40 | set(CFITSIO_FOUND TRUE) 41 | else (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) 42 | set(CFITSIO_FOUND FALSE) 43 | endif(CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) 44 | 45 | 46 | if (CFITSIO_FOUND) 47 | 48 | # Find the version of the cfitsio header 49 | execute_process(COMMAND egrep CFITSIO_VERSION ${CFITSIO_INCLUDE_DIR}/fitsio.h 50 | OUTPUT_VARIABLE CFITSIO_VERSION_STRING) 51 | STRING(REGEX REPLACE "[^0-9.]" "" CFITSIO_VERSION_STRING ${CFITSIO_VERSION_STRING}) 52 | STRING(REGEX REPLACE "^([0-9]+)[.]([0-9]+)" "\\1" CFITSIO_VERSION_MAJOR ${CFITSIO_VERSION_STRING}) 53 | STRING(REGEX REPLACE "^([0-9]+)[.]([0-9]+)" "\\2" CFITSIO_VERSION_MINOR ${CFITSIO_VERSION_STRING}) 54 | 55 | if (NOT CFITSIO_FIND_QUIETLY) 56 | message(STATUS "Found CFITSIO ${CFITSIO_VERSION_STRING}: ${CFITSIO_LIBRARIES}") 57 | endif (NOT CFITSIO_FIND_QUIETLY) 58 | else (CFITSIO_FOUND) 59 | if (CFITSIO_FIND_REQUIRED) 60 | message(STATUS "CFITSIO not found.") 61 | endif (CFITSIO_FIND_REQUIRED) 62 | endif (CFITSIO_FOUND) 63 | 64 | mark_as_advanced(CFITSIO_INCLUDE_DIR CFITSIO_LIBRARIES) 65 | 66 | endif (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) 67 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindALUT.cmake: -------------------------------------------------------------------------------- 1 | # - Locate ALUT 2 | # This module defines 3 | # ALUT_LIBRARY 4 | # ALUT_FOUND, if false, do not try to link to OpenAL 5 | # ALUT_INCLUDE_DIR, where to find the headers 6 | # 7 | # $OPENALDIR is an environment variable that would 8 | # correspond to the ./configure --prefix=$OPENALDIR 9 | # used in building OpenAL. 10 | # 11 | # Created by Bryan Donlan, based on the FindOpenAL.cmake module by Eric Wang. 12 | 13 | FIND_PATH(ALUT_INCLUDE_DIR alut.h 14 | $ENV{OPENALDIR}/include 15 | ~/Library/Frameworks/OpenAL.framework/Headers 16 | /Library/Frameworks/OpenAL.framework/Headers 17 | /System/Library/Frameworks/OpenAL.framework/Headers # Tiger 18 | /usr/local/include/AL 19 | /usr/local/include/OpenAL 20 | /usr/local/include 21 | /usr/include/AL 22 | /usr/include/OpenAL 23 | /usr/include 24 | /sw/include/AL # Fink 25 | /sw/include/OpenAL 26 | /sw/include 27 | /opt/local/include/AL # DarwinPorts 28 | /opt/local/include/OpenAL 29 | /opt/local/include 30 | /opt/csw/include/AL # Blastwave 31 | /opt/csw/include/OpenAL 32 | /opt/csw/include 33 | /opt/include/AL 34 | /opt/include/OpenAL 35 | /opt/include 36 | ) 37 | # I'm not sure if I should do a special casing for Apple. It is 38 | # unlikely that other Unix systems will find the framework path. 39 | # But if they do ([Next|Open|GNU]Step?), 40 | # do they want the -framework option also? 41 | IF(${ALUT_INCLUDE_DIR} MATCHES ".framework") 42 | STRING(REGEX REPLACE "(.*)/.*\\.framework/.*" "\\1" ALUT_FRAMEWORK_PATH_TMP ${ALUT_INCLUDE_DIR}) 43 | IF("${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/Library/Frameworks" 44 | OR "${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/System/Library/Frameworks" 45 | ) 46 | # String is in default search path, don't need to use -F 47 | SET (ALUT_LIBRARY "-framework OpenAL" CACHE STRING "OpenAL framework for OSX") 48 | ELSE("${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/Library/Frameworks" 49 | OR "${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/System/Library/Frameworks" 50 | ) 51 | # String is not /Library/Frameworks, need to use -F 52 | SET(ALUT_LIBRARY "-F${ALUT_FRAMEWORK_PATH_TMP} -framework OpenAL" CACHE STRING "OpenAL framework for OSX") 53 | ENDIF("${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/Library/Frameworks" 54 | OR "${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/System/Library/Frameworks" 55 | ) 56 | # Clear the temp variable so nobody can see it 57 | SET(ALUT_FRAMEWORK_PATH_TMP "" CACHE INTERNAL "") 58 | 59 | ELSE(${ALUT_INCLUDE_DIR} MATCHES ".framework") 60 | FIND_LIBRARY(ALUT_LIBRARY 61 | NAMES alut 62 | PATHS 63 | $ENV{OPENALDIR}/lib 64 | $ENV{OPENALDIR}/libs 65 | /usr/local/lib 66 | /usr/lib 67 | /sw/lib 68 | /opt/local/lib 69 | /opt/csw/lib 70 | /opt/lib 71 | ) 72 | ENDIF(${ALUT_INCLUDE_DIR} MATCHES ".framework") 73 | 74 | SET(ALUT_FOUND "NO") 75 | IF(ALUT_LIBRARY) 76 | SET(ALUT_FOUND "YES") 77 | ENDIF(ALUT_LIBRARY) 78 | -------------------------------------------------------------------------------- /device/rpi/web/charts.py: -------------------------------------------------------------------------------- 1 | import os 2 | import matplotlib 3 | import sqlite3 4 | matplotlib.use('Agg') 5 | from matplotlib import pyplot as plt 6 | import pandas as pd 7 | import math 8 | 9 | class ChartGenerator: 10 | 11 | NAME = 'ChartGenerator' 12 | HISTORICAL_DATA_SQL = "SELECT rain,sky_temperature, ambient_temperature, date_sensor_read FROM weather_sensor WHERE date_sensor_read >= date('now','-24 hour')" 13 | MIN_SKY_TEMP_HISTORY = "SELECT min(sky_temperature) as min_sky_temperature FROM weather_sensor WHERE date_sensor_read >= date('now','-10 day')" 14 | 15 | def __init__(self, root_dir): 16 | self.root_dir = root_dir 17 | plt.rcParams["figure.figsize"] = (10, 3) 18 | plt.style.use('bmh') 19 | self._conn = sqlite3.connect('weather_sensor.db') 20 | 21 | 22 | def _calculate_cloud_cover(self, sky, ambient, recent_clear_sky_temp): 23 | ''' 24 | :param sky: 25 | :param ambient: 26 | :param recent_clear_sky_temp 27 | :return: 28 | ''' 29 | print(recent_clear_sky_temp) 30 | scaling_factor = 100 / abs(recent_clear_sky_temp) 31 | x = abs(((sky * -1) * scaling_factor) - 75) 32 | if x < 0: 33 | return 0 34 | elif x > 100: 35 | return 100 36 | else: 37 | return x 38 | 39 | def generate_cloud_chart(self): 40 | weather = self._last_24hrs_data() 41 | recent_clear_sky_temp = self._min_sky_last_month() 42 | weather['CloudCover'] = weather.apply(lambda x: self._calculate_cloud_cover(x['sky_temperature'], x['ambient_temperature'], recent_clear_sky_temp), axis=1) 43 | weather['Rain'] = weather[['rain']]*100 44 | rain_clouds = weather.loc[:,['Rain','CloudCover']] 45 | rain_clouds.resample('5T').mean().plot(); 46 | ax = rain_clouds.plot(); 47 | ax.set_ylabel("%") 48 | plt.savefig(os.path.join(self.root_dir, './cloud.png'), bbox_inches='tight') 49 | plt.clf() 50 | plt.close() 51 | 52 | def _last_24hrs_data(self): 53 | conn = sqlite3.connect('weather_sensor.db') 54 | with conn: 55 | weather = pd.read_sql(self.HISTORICAL_DATA_SQL, self._conn) 56 | weather = weather.rename(columns={'date_sensor_read': 'Time'}) 57 | weather.index = pd.to_datetime(weather.Time) 58 | return weather 59 | 60 | def _min_sky_last_month(self): 61 | conn = sqlite3.connect('weather_sensor.db') 62 | with conn: 63 | cursor=conn.cursor() 64 | cursor.execute(self.MIN_SKY_TEMP_HISTORY) 65 | mintemp = cursor.fetchone()[0] 66 | if mintemp > -5 or mintemp < -25: 67 | return -20 #-20 is a good guess for 100% clear sky 68 | else: 69 | return mintemp 70 | 71 | def generate_temperature_chart(self): 72 | weather = self._last_24hrs_data() 73 | temperatures = weather.loc[:, ['sky_temperature','ambient_temperature']] 74 | ax = temperatures.plot(); 75 | ax.set_ylabel("Temp Deg C") 76 | plt.savefig(os.path.join(self.root_dir, './temperature.png'), bbox_inches='tight') 77 | plt.clf() 78 | plt.close() 79 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindGPHOTO2.cmake: -------------------------------------------------------------------------------- 1 | # - Find the native sqlite3 includes and library 2 | # 3 | # This module defines 4 | # GPHOTO2_INCLUDE_DIR, where to find libgphoto2 header files 5 | # GPHOTO2_LIBRARIES, the libraries to link against to use libgphoto2 6 | # GPHOTO2_FOUND, If false, do not try to use libgphoto2. 7 | # GPHOTO2_VERSION_STRING, e.g. 2.4.14 8 | # GPHOTO2_VERSION_MAJOR, e.g. 2 9 | # GPHOTO2_VERSION_MINOR, e.g. 4 10 | # GPHOTO2_VERSION_PATCH, e.g. 14 11 | # 12 | # also defined, but not for general use are 13 | # GPHOTO2_LIBRARY, where to find the sqlite3 library. 14 | 15 | 16 | #============================================================================= 17 | # Copyright 2010 henrik andersson 18 | #============================================================================= 19 | 20 | SET(GPHOTO2_FIND_REQUIRED ${Gphoto2_FIND_REQUIRED}) 21 | 22 | find_path(GPHOTO2_INCLUDE_DIR gphoto2/gphoto2.h) 23 | mark_as_advanced(GPHOTO2_INCLUDE_DIR) 24 | 25 | set(GPHOTO2_NAMES ${GPHOTO2_NAMES} gphoto2 libgphoto2) 26 | set(GPHOTO2_PORT_NAMES ${GPHOTO2_PORT_NAMES} gphoto2_port libgphoto2_port) 27 | find_library(GPHOTO2_LIBRARY NAMES ${GPHOTO2_NAMES} ) 28 | find_library(GPHOTO2_PORT_LIBRARY NAMES ${GPHOTO2_PORT_NAMES} ) 29 | mark_as_advanced(GPHOTO2_LIBRARY) 30 | mark_as_advanced(GPHOTO2_PORT_LIBRARY) 31 | 32 | # Detect libgphoto2 version 33 | FIND_PROGRAM(GPHOTO2CONFIG_EXECUTABLE NAMES gphoto2-config) 34 | IF(GPHOTO2CONFIG_EXECUTABLE) 35 | EXEC_PROGRAM(${GPHOTO2CONFIG_EXECUTABLE} ARGS --version RETURN_VALUE _return_VALUE OUTPUT_VARIABLE GPHOTO2_VERSION) 36 | string(REGEX REPLACE "^.*libgphoto2 ([0-9]+).*$" "\\1" GPHOTO2_VERSION_MAJOR "${GPHOTO2_VERSION}") 37 | string(REGEX REPLACE "^.*libgphoto2 [0-9]+\\.([0-9]+).*$" "\\1" GPHOTO2_VERSION_MINOR "${GPHOTO2_VERSION}") 38 | string(REGEX REPLACE "^.*libgphoto2 [0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" GPHOTO2_VERSION_PATCH "${GPHOTO2_VERSION}") 39 | 40 | set(GPHOTO2_VERSION_STRING "${GPHOTO2_VERSION_MAJOR}.${GPHOTO2_VERSION_MINOR}.${GPHOTO2_VERSION_PATCH}") 41 | ENDIF(GPHOTO2CONFIG_EXECUTABLE) 42 | 43 | # handle the QUIETLY and REQUIRED arguments and set GPHOTO2_FOUND to TRUE if 44 | # all listed variables are TRUE 45 | include(FindPackageHandleStandardArgs) 46 | find_package_handle_standard_args(GPHOTO2 DEFAULT_MSG GPHOTO2_LIBRARY GPHOTO2_INCLUDE_DIR) 47 | 48 | IF(GPHOTO2_FOUND) 49 | SET(Gphoto2_LIBRARIES ${GPHOTO2_LIBRARY} ${GPHOTO2_PORT_LIBRARY}) 50 | SET(Gphoto2_INCLUDE_DIRS ${GPHOTO2_INCLUDE_DIR}) 51 | 52 | # libgphoto2 dynamically loads and unloads usb library 53 | # without calling any cleanup functions (since they are absent from libusb-0.1). 54 | # This leaves usb event handling threads running with invalid callback and return addresses, 55 | # which causes a crash after any usb event is generated, at least in Mac OS X. 56 | # libusb1 backend does correctly call exit function, but ATM it crashes anyway. 57 | # Workaround is to link against libusb so that it wouldn't get unloaded. 58 | IF(APPLE) 59 | find_library(USB_LIBRARY NAMES usb-1.0 libusb-1.0) 60 | mark_as_advanced(USB_LIBRARY) 61 | IF(USB_LIBRARY) 62 | SET(Gphoto2_LIBRARIES ${Gphoto2_LIBRARIES} ${USB_LIBRARY}) 63 | ENDIF(USB_LIBRARY) 64 | ENDIF(APPLE) 65 | 66 | ENDIF(GPHOTO2_FOUND) 67 | -------------------------------------------------------------------------------- /device/rpi/web/weatherMicroService.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sqlite3 4 | from bottle import route, run, debug, error, request, static_file 5 | from collector import Collector 6 | from charts import ChartGenerator 7 | 8 | ''' 9 | A very simple python bottle micro service for weather 10 | ''' 11 | 12 | @route('/weather/current') 13 | def current_weather(): 14 | ''' 15 | GET the current weather state. the latest reading persisted in the DB. 16 | TODO: If the reading is older than 5min then return 404? 17 | :return: 18 | ''' 19 | conn = sqlite3.connect('weather_sensor.db') 20 | c = conn.cursor() 21 | c.execute("SELECT rain,sky_temperature,ambient_temperature, date_sensor_read FROM weather_sensor order by id desc limit 1") 22 | result = c.fetchall() 23 | c.close() 24 | sky_temp = result[0][1] 25 | outside_temp = result[0][2] 26 | reading_timestamp = result[0][3] 27 | #rain = (result[0][0] == 1 and sky_temp - outside_temp > -20 and sky_temp > -10) #hack to prevent a true for rain when the sky is clear. Sometimes dew triggers a false positive for rain 28 | rain = result[0][0] == 1 29 | return {'rain': rain, 'skyTemp': sky_temp, 'outsideTemp': outside_temp, 'readingTimestamp': reading_timestamp} 30 | 31 | @route('/weather/history') 32 | def historical_weather(): 33 | ''' 34 | Return historical weather data. Pass days=x as a qurey string arg to get the previous x days data. 35 | :return: 36 | ''' 37 | conn = sqlite3.connect('weather_sensor.db') 38 | c = conn.cursor() 39 | days = request.query.days or 1 40 | c.execute("SELECT rain,sky_temperature, ambient_temperature, date_sensor_read FROM weather_sensor WHERE date_sensor_read >= date('now','-{} day')".format(days)) 41 | result = c.fetchall() 42 | c.close() 43 | history = [] 44 | count =0 45 | for row in result: 46 | count += 1 47 | history.append({'rain': row[0] == 1, 'skyTemp': row[1], 'outsideTemp': row[2], 'readingTimestamp' : row[3]}) 48 | return {'count': count, 'history': history} 49 | 50 | @route('/weather/chart/') 51 | def cloud_chart(chart): 52 | if 'cloud.png' in chart: 53 | _chartGenerator.generate_cloud_chart() 54 | else: 55 | _chartGenerator.generate_temperature_chart() 56 | return static_file(chart, root='/tmp') 57 | 58 | @route('/weather/safety') 59 | def safety(): 60 | ''' 61 | GET the current weather state. the latest reading persisted in the DB. 62 | TODO: If the reading is older than 5min then return 404? 63 | :return: 64 | ''' 65 | conn = sqlite3.connect('weather_sensor.db') 66 | c = conn.cursor() 67 | c.execute("SELECT rain,sky_temperature,ambient_temperature, date_sensor_read FROM weather_sensor order by id desc limit 1") 68 | result = c.fetchall() 69 | c.close() 70 | sky_temp = result[0][1] 71 | outside_temp = result[0][2] 72 | reading_timestamp = result[0][3] 73 | raining = (result[0][0] == 1 and sky_temp - outside_temp > -20 and sky_temp > -10) #hack to prevent a true for rain when the sky is clear. Sometimes dew triggers a false positive for rain 74 | roof_status = {'open_ok': 1, 'reasons': ''} 75 | if sky_temp - outside_temp > -17: 76 | roof_status = {'open_ok': 0, 'reasons': 'Cloudy'} 77 | if raining: 78 | roof_status = {'open_ok': 0, 'reasons': 'Raining'} 79 | return {'timestamp_utc': reading_timestamp, 'roof_status': roof_status} 80 | 81 | 82 | _chartGenerator = ChartGenerator('/tmp') 83 | con = sqlite3.connect('weather_sensor.db') 84 | con.execute("CREATE TABLE IF NOT EXISTS weather_sensor (id INTEGER PRIMARY KEY, rain bool NOT NULL, sky_temperature NUMBER NOT NULL, ambient_temperature NUMBER NOT NULL, date_sensor_read DATETIME DEFAULT CURRENT_TIMESTAMP)") 85 | con.commit() 86 | collector = Collector('/dev/ttyACM0') 87 | run(host='0.0.0.0', port=8080) 88 | -------------------------------------------------------------------------------- /device/rpi/web/collector.py: -------------------------------------------------------------------------------- 1 | from pyfirmata import Arduino, util 2 | import pyfirmata 3 | import sqlite3 4 | import json 5 | import time 6 | 7 | 8 | class Collector(): 9 | """ 10 | Handles the communication to arduino SensorReader 11 | The arduino firmware publishes messages using firmata once per second with sensor readings. 12 | This class is responsible for collection and persistance of readings. 13 | AttachTo: "" 14 | """ 15 | 16 | NAME = "Collector" 17 | 18 | def __init__(self, port): 19 | ''' 20 | Constructor. Adds the callback handler to accept firmata messages from the arduino board connected to the sensors. 21 | ''' 22 | self.last_rain_reading_saved = None; 23 | self.last_sky_temperature_reading_saved = 0; 24 | self.last_ambient_temperature_reading_saved = 0; 25 | self.last_reading_saved_time = time.time() 26 | self.board = Arduino(port) 27 | # start an iterator thread so that serial buffer doesn't overflow 28 | it = util.Iterator(self.board) 29 | it.start() 30 | self.board.add_cmd_handler(pyfirmata.pyfirmata.STRING_DATA, self._messageHandler) 31 | 32 | def _messageHandler(self, *args, **kwargs): 33 | ''' 34 | Calback method envoked by the firmata library. Handles the string message sent from the arduino. 35 | Grabs the sensor data from the message and persists in the DB table. 36 | :param args: 37 | :param kwargs: 38 | :return: 39 | ''' 40 | readings = json.loads(util.two_byte_iter_to_str(args)) 41 | sky_temperature = readings['sky'] 42 | ambient_temperature = readings['ambient'] 43 | rain = readings['rain'] 44 | if self.should_persist_sensor_reading(sky_temperature, ambient_temperature, rain): 45 | conn = sqlite3.connect('weather_sensor.db') 46 | c = conn.cursor() 47 | print('inserting observation') 48 | c.execute("INSERT INTO weather_sensor (rain,sky_temperature,ambient_temperature) VALUES (?,?,?)", 49 | (rain, sky_temperature, ambient_temperature)) 50 | c.execute("DELETE FROM weather_sensor WHERE date_sensor_read <= date('now','-365 day')") 51 | print('inserted') 52 | # new_id = c.lastrowid 53 | conn.commit() 54 | self.last_rain_reading_saved = rain 55 | self.last_sky_temperature_reading_saved = sky_temperature 56 | self.last_ambient_temperature_reading_saved = ambient_temperature 57 | self.last_reading_saved_time = time.time() 58 | c.close() 59 | 60 | def update(self): 61 | super(Collector, self).update() 62 | 63 | def writeData(self, data): 64 | self.board.send_sysex(pyfirmata.pyfirmata.STRING_DATA, data) 65 | 66 | def dispose(self): 67 | super(Collector, self).dispose() 68 | try: 69 | self.board.exit() 70 | except AttributeError: 71 | print('exit() raised an AttributeError unexpectedly!') 72 | 73 | 74 | def should_persist_sensor_reading(self, sky_temperature, ambient_temperature, rain): 75 | ''' 76 | Returns true if the sensor data should be persisted in the DB. 77 | The rules are if any temp change is more than 1 degree, or the rain state changes 78 | or 60sec have elapsed since the last save 79 | :param sky_temperature: 80 | :param ambient_temperature: 81 | :param rain: 82 | :return: 83 | ''' 84 | if abs(sky_temperature - self.last_sky_temperature_reading_saved) > 1 or abs( 85 | ambient_temperature - self.last_ambient_temperature_reading_saved) > 1 or rain != self.last_rain_reading_saved or time.time() - self.last_reading_saved_time > 60: 86 | return True 87 | else: 88 | return False 89 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindOpenAL.cmake: -------------------------------------------------------------------------------- 1 | # Locate OpenAL 2 | # This module defines 3 | # OPENAL_LIBRARY 4 | # OPENAL_FOUND, if false, do not try to link to OpenAL 5 | # OPENAL_INCLUDE_DIR, where to find the headers 6 | # 7 | # $OPENALDIR is an environment variable that would 8 | # correspond to the ./configure --prefix=$OPENALDIR 9 | # used in building OpenAL. 10 | # 11 | # Created by Eric Wing. This was influenced by the FindSDL.cmake module. 12 | 13 | # This makes the presumption that you are include al.h like 14 | # #include "al.h" 15 | # and not 16 | # #include 17 | # The reason for this is that the latter is not entirely portable. 18 | # Windows/Creative Labs does not by default put their headers in AL/ and 19 | # OS X uses the convention . 20 | # 21 | # For Windows, Creative Labs seems to have added a registry key for their 22 | # OpenAL 1.1 installer. I have added that key to the list of search paths, 23 | # however, the key looks like it could be a little fragile depending on 24 | # if they decide to change the 1.00.0000 number for bug fix releases. 25 | # Also, they seem to have laid down groundwork for multiple library platforms 26 | # which puts the library in an extra subdirectory. Currently there is only 27 | # Win32 and I have hardcoded that here. This may need to be adjusted as 28 | # platforms are introduced. 29 | # The OpenAL 1.0 installer doesn't seem to have a useful key I can use. 30 | # I do not know if the Nvidia OpenAL SDK has a registry key. 31 | # 32 | # For OS X, remember that OpenAL was added by Apple in 10.4 (Tiger). 33 | # To support the framework, I originally wrote special framework detection 34 | # code in this module which I have now removed with CMake's introduction 35 | # of native support for frameworks. 36 | # In addition, OpenAL is open source, and it is possible to compile on Panther. 37 | # Furthermore, due to bugs in the initial OpenAL release, and the 38 | # transition to OpenAL 1.1, it is common to need to override the built-in 39 | # framework. 40 | # Per my request, CMake should search for frameworks first in 41 | # the following order: 42 | # ~/Library/Frameworks/OpenAL.framework/Headers 43 | # /Library/Frameworks/OpenAL.framework/Headers 44 | # /System/Library/Frameworks/OpenAL.framework/Headers 45 | # 46 | # On OS X, this will prefer the Framework version (if found) over others. 47 | # People will have to manually change the cache values of 48 | # OPENAL_LIBRARY to override this selection or set the CMake environment 49 | # CMAKE_INCLUDE_PATH to modify the search paths. 50 | 51 | FIND_PATH(OPENAL_INCLUDE_DIR al.h 52 | PATHS 53 | $ENV{OPENALDIR} 54 | NO_DEFAULT_PATH 55 | PATH_SUFFIXES include/AL include/OpenAL include 56 | ) 57 | 58 | FIND_PATH(OPENAL_INCLUDE_DIR al.h 59 | PATHS 60 | ~/Library/Frameworks 61 | /Library/Frameworks 62 | /usr/local 63 | /usr 64 | /sw # Fink 65 | /opt/local # DarwinPorts 66 | /opt/csw # Blastwave 67 | /opt 68 | [HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir] 69 | PATH_SUFFIXES include/AL include/OpenAL include 70 | ) 71 | 72 | FIND_LIBRARY(OPENAL_LIBRARY 73 | NAMES OpenAL al openal OpenAL32 74 | PATHS 75 | $ENV{OPENALDIR} 76 | NO_DEFAULT_PATH 77 | PATH_SUFFIXES lib64 lib libs64 libs libs/Win32 libs/Win64 78 | ) 79 | 80 | FIND_LIBRARY(OPENAL_LIBRARY 81 | NAMES OpenAL al openal OpenAL32 82 | PATHS 83 | ~/Library/Frameworks 84 | /Library/Frameworks 85 | /usr/local 86 | /usr 87 | /sw 88 | /opt/local 89 | /opt/csw 90 | /opt 91 | [HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir] 92 | PATH_SUFFIXES lib64 lib libs64 libs libs/Win32 libs/Win64 93 | ) 94 | 95 | 96 | SET(OPENAL_FOUND "NO") 97 | IF(OPENAL_LIBRARY AND OPENAL_INCLUDE_DIR) 98 | SET(OPENAL_FOUND "YES") 99 | ENDIF(OPENAL_LIBRARY AND OPENAL_INCLUDE_DIR) 100 | 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cloud-rain-monitor 2 | 3 | An Arduino firmware, Raspberry PI application and indi-driver for a device to measure rain and cloud cover for an astronomical observatory. Cloud cover is determined by measuring the difference between ambient temperature and sky temperature. 4 | 5 | **Outside** 6 | 7 | ![](https://raw.githubusercontent.com/dokeeffe/cloud-rain-monitor/master/readme-files/weatherstation1.png) 8 | 9 | **Inside** 10 | 11 | ![](https://raw.githubusercontent.com/dokeeffe/cloud-rain-monitor/master/readme-files/weatherstation2.png) 12 | 13 | The device offers an HTTP interface to GET current conditions. See below for the full API 14 | 15 | Example request to /weather 16 | ``` 17 | { 18 | "outsideTemp": 2.75, 19 | "skyTemp": -21.77, 20 | "readingTimestamp": 21 | "2018-03-25 18:02:46", 22 | "rain": false 23 | } 24 | ``` 25 | 26 | Clouds are detected using an Melexis [MLX90614](http://www.melexis.com/Infrared-Thermometer-Sensors/Infrared-Thermometer-Sensors/MLX90614-615.aspx) sensor to measure IR radiation from the sky. 27 | ![MLX90614](https://www.melexis.com/-/media/images/product-media/mlx90614/mlx90614-infrared-thermometer-melexis.jpg?h=275&w=340&hash=327FA5D17A6484712BE79EDAE1A8D6282C376334) 28 | 29 | Rain is detected using an [RG-11 rain sensor](http://rainsensors.com/) 30 | ![rg-11](http://hydreon.com/wp-content/uploads/sites/3/2015/rg_wht_sm.jpg) 31 | 32 | An [Indi Driver](http://www.indilib.org/devices/weather-stations.html) for observatory automation is also included. 33 | 34 | ![indi-driver](https://raw.githubusercontent.com/dokeeffe/cloud-rain-monitor/master/indi-driver/docs/indi.png) 35 | 36 | 37 | The device and driver is currently used in Ballyhoura Observatory 38 | 39 | ![observatory](https://raw.githubusercontent.com/dokeeffe/cloud-rain-monitor/master/indi-driver/docs/obs.jpeg) 40 | 41 | # Build notes/instructions 42 | 43 | * 1 Flash the ino file to an arduino nano. 44 | 45 | * 2 Wiring diagram (in progress) 46 | 47 | * 3 Clone this repo to raspberry pi then add a line to /etc/rc.local to start the weather micro service on startup 48 | 49 | ``` 50 | 51 | # start the weatherstation 52 | /home/pi/code/github/cloud-rain-monitor/device/rpi/web/weatherMicroService.py & 53 | ``` 54 | 55 | # HTTP API 56 | 57 | **Current weather status** 58 | ---- 59 | 60 | * **URL** 61 | 62 | /weather/current 63 | 64 | * **Method:** 65 | 66 | `GET` 67 | 68 | * **Success Response:** 69 | 70 | * **Code:** 200
71 | **Content:** `{"outsideTemp": 2.75, "skyTemp": -21.77, "readingTimestamp": "2018-03-25 18:02:46", "rain": false}` 72 | 73 | **Historical weather** 74 | ---- 75 | 76 | Returns history for the previous 24 hours 77 | 78 | * **URL** 79 | 80 | /weather/history 81 | 82 | * **Method:** 83 | 84 | `GET` 85 | 86 | * **Success Response:** 87 | 88 | * **Code:** 200
89 | **Content:** `[{"outsideTemp": 2.75, "skyTemp": -21.77, "readingTimestamp": "2018-03-25 18:02:46", "rain": false}, {"outsideTemp": 2.75, "skyTemp": -21.77, "readingTimestamp": "2018-03-25 18:02:46", "rain": false}....]` 90 | 91 | 92 | **Charts** 93 | ---- 94 | 95 | Returns an image weather chart 96 | 97 | * **URL** 98 | 99 | /weather/chart/ 100 | 101 | * **Method:** 102 | 103 | `GET` 104 | 105 | * **URL Params** 106 | 107 | **Required:** 108 | 109 | `` 110 | 111 | Valid values are 'cloud.png' and 'temperature.png' 112 | 113 | * **Sample Call:** 114 | 115 | http://192.168.2.227:8080/weather/chart/cloud.png 116 | 117 | * **Success Response:** 118 | 119 | * **Code:** 200
120 | **Content:** 121 | 122 | ![example measurements](https://raw.githubusercontent.com/dokeeffe/cloud-rain-monitor/master/readme-files/temperature.png "Example measurements") 123 | 124 | ![example measurements](https://raw.githubusercontent.com/dokeeffe/cloud-rain-monitor/master/readme-files/cloud.png "Example measurements") 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindUSB-1.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find libusb-1.0 2 | # Once done this will define 3 | # 4 | # LIBUSB_1_FOUND - system has libusb 5 | # LIBUSB_1_INCLUDE_DIRS - the libusb include directory 6 | # LIBUSB_1_LIBRARIES - Link these to use libusb 7 | # LIBUSB_1_DEFINITIONS - Compiler switches required for using libusb 8 | # 9 | # Adapted from cmake-modules Google Code project 10 | # 11 | # Copyright (c) 2006 Andreas Schneider 12 | # 13 | # (Changes for libusb) Copyright (c) 2008 Kyle Machulis 14 | # 15 | # Redistribution and use is allowed according to the terms of the New BSD license. 16 | # 17 | # CMake-Modules Project New BSD License 18 | # 19 | # Redistribution and use in source and binary forms, with or without 20 | # modification, are permitted provided that the following conditions are met: 21 | # 22 | # * Redistributions of source code must retain the above copyright notice, this 23 | # list of conditions and the following disclaimer. 24 | # 25 | # * Redistributions in binary form must reproduce the above copyright notice, 26 | # this list of conditions and the following disclaimer in the 27 | # documentation and/or other materials provided with the distribution. 28 | # 29 | # * Neither the name of the CMake-Modules Project nor the names of its 30 | # contributors may be used to endorse or promote products derived from this 31 | # software without specific prior written permission. 32 | # 33 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 34 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 35 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 36 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 37 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 38 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 39 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 40 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 41 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 42 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 43 | # 44 | 45 | if (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) 46 | # in cache already 47 | set(LIBUSB_FOUND TRUE) 48 | else (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) 49 | find_path(LIBUSB_1_INCLUDE_DIR 50 | NAMES 51 | libusb.h 52 | PATHS 53 | /usr/include 54 | /usr/local/include 55 | /opt/local/include 56 | /sw/include 57 | PATH_SUFFIXES 58 | libusb-1.0 59 | ) 60 | 61 | find_library(LIBUSB_1_LIBRARY 62 | NAMES 63 | usb-1.0 64 | PATHS 65 | /usr/lib 66 | /usr/local/lib 67 | /opt/local/lib 68 | /sw/lib 69 | ) 70 | 71 | set(LIBUSB_1_INCLUDE_DIRS 72 | ${LIBUSB_1_INCLUDE_DIR} 73 | ) 74 | set(LIBUSB_1_LIBRARIES 75 | ${LIBUSB_1_LIBRARY} 76 | ) 77 | 78 | if (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) 79 | set(LIBUSB_1_FOUND TRUE) 80 | endif (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) 81 | 82 | if (LIBUSB_1_FOUND) 83 | if (NOT USB-1_FIND_QUIETLY) 84 | message(STATUS "Found libusb-1.0:") 85 | message(STATUS " - Includes: ${LIBUSB_1_INCLUDE_DIRS}") 86 | message(STATUS " - Libraries: ${LIBUSB_1_LIBRARIES}") 87 | endif (NOT USB-1_FIND_QUIETLY) 88 | set(CMAKE_REQUIRED_INCLUDES ${LIBUSB_1_INCLUDE_DIRS}) 89 | set(CMAKE_REQUIRED_LIBRARIES ${LIBUSB_1_LIBRARIES}) 90 | if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") 91 | include (CheckCXXSourceCompiles) 92 | check_cxx_source_compiles("#include 93 | int main() { libusb_error_name(0); return 0; }" ERROR_NAME_COMPILE) 94 | if (NOT ERROR_NAME_COMPILE) 95 | add_definitions("-DNO_ERROR_NAME") 96 | message(STATUS " - 1.0.8 or older") 97 | endif (NOT ERROR_NAME_COMPILE) 98 | endif () 99 | else (LIBUSB_1_FOUND) 100 | if (USB-1_FIND_REQUIRED) 101 | message(FATAL_ERROR "Could not find libusb-1.0. Please install libusb-1.0 along with the development package.") 102 | endif (USB-1_FIND_REQUIRED) 103 | endif (LIBUSB_1_FOUND) 104 | 105 | # show the LIBUSB_1_INCLUDE_DIRS and LIBUSB_1_LIBRARIES variables only in the advanced view 106 | mark_as_advanced(LIBUSB_1_INCLUDE_DIRS LIBUSB_1_LIBRARIES) 107 | 108 | endif (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) 109 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/gason.h: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2013-2015 Ivan Vashchaev 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #pragma once 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | enum JsonTag { 31 | JSON_NUMBER = 0, 32 | JSON_STRING, 33 | JSON_ARRAY, 34 | JSON_OBJECT, 35 | JSON_TRUE, 36 | JSON_FALSE, 37 | JSON_NULL = 0xF 38 | }; 39 | 40 | struct JsonNode; 41 | 42 | #define JSON_VALUE_PAYLOAD_MASK 0x00007FFFFFFFFFFFULL 43 | #define JSON_VALUE_NAN_MASK 0x7FF8000000000000ULL 44 | #define JSON_VALUE_TAG_MASK 0xF 45 | #define JSON_VALUE_TAG_SHIFT 47 46 | 47 | union JsonValue { 48 | uint64_t ival; 49 | double fval; 50 | 51 | JsonValue(double x) 52 | : fval(x) { 53 | } 54 | JsonValue(JsonTag tag = JSON_NULL, void *payload = nullptr) { 55 | assert((uint64_t)(uintptr_t)payload <= JSON_VALUE_PAYLOAD_MASK); 56 | ival = JSON_VALUE_NAN_MASK | ((uint64_t)tag << JSON_VALUE_TAG_SHIFT) | (uintptr_t)payload; 57 | } 58 | bool isDouble() const { 59 | return (int64_t)ival <= (int64_t)JSON_VALUE_NAN_MASK; 60 | } 61 | JsonTag getTag() const { 62 | return isDouble() ? JSON_NUMBER : JsonTag((ival >> JSON_VALUE_TAG_SHIFT) & JSON_VALUE_TAG_MASK); 63 | } 64 | uint64_t getPayload() const { 65 | assert(!isDouble()); 66 | return ival & JSON_VALUE_PAYLOAD_MASK; 67 | } 68 | double toNumber() const { 69 | assert(getTag() == JSON_NUMBER); 70 | return fval; 71 | } 72 | char *toString() const { 73 | assert(getTag() == JSON_STRING); 74 | return (char *)getPayload(); 75 | } 76 | JsonNode *toNode() const { 77 | assert(getTag() == JSON_ARRAY || getTag() == JSON_OBJECT); 78 | return (JsonNode *)getPayload(); 79 | } 80 | }; 81 | 82 | struct JsonNode { 83 | JsonValue value; 84 | JsonNode *next; 85 | char *key; 86 | }; 87 | 88 | struct JsonIterator { 89 | JsonNode *p; 90 | 91 | void operator++() { 92 | p = p->next; 93 | } 94 | bool operator!=(const JsonIterator &x) const { 95 | return p != x.p; 96 | } 97 | JsonNode *operator*() const { 98 | return p; 99 | } 100 | JsonNode *operator->() const { 101 | return p; 102 | } 103 | }; 104 | 105 | inline JsonIterator begin(JsonValue o) { 106 | return JsonIterator{o.toNode()}; 107 | } 108 | inline JsonIterator end(JsonValue) { 109 | return JsonIterator{nullptr}; 110 | } 111 | 112 | #define JSON_ERRNO_MAP(XX) \ 113 | XX(OK, "ok") \ 114 | XX(BAD_NUMBER, "bad number") \ 115 | XX(BAD_STRING, "bad string") \ 116 | XX(BAD_IDENTIFIER, "bad identifier") \ 117 | XX(STACK_OVERFLOW, "stack overflow") \ 118 | XX(STACK_UNDERFLOW, "stack underflow") \ 119 | XX(MISMATCH_BRACKET, "mismatch bracket") \ 120 | XX(UNEXPECTED_CHARACTER, "unexpected character") \ 121 | XX(UNQUOTED_KEY, "unquoted key") \ 122 | XX(BREAKING_BAD, "breaking bad") \ 123 | XX(ALLOCATION_FAILURE, "allocation failure") 124 | 125 | enum JsonErrno { 126 | #define XX(no, str) JSON_##no, 127 | JSON_ERRNO_MAP(XX) 128 | #undef XX 129 | }; 130 | 131 | const char *jsonStrError(int err); 132 | 133 | class JsonAllocator { 134 | struct Zone { 135 | Zone *next; 136 | size_t used; 137 | } *head = nullptr; 138 | 139 | public: 140 | JsonAllocator() = default; 141 | JsonAllocator(const JsonAllocator &) = delete; 142 | JsonAllocator &operator=(const JsonAllocator &) = delete; 143 | JsonAllocator(JsonAllocator &&x) : head(x.head) { 144 | x.head = nullptr; 145 | } 146 | JsonAllocator &operator=(JsonAllocator &&x) { 147 | head = x.head; 148 | x.head = nullptr; 149 | return *this; 150 | } 151 | ~JsonAllocator() { 152 | deallocate(); 153 | } 154 | void *allocate(size_t size); 155 | void deallocate(); 156 | }; 157 | 158 | int jsonParse(char *str, char **endptr, JsonValue *value, JsonAllocator &allocator); 159 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/MacroLogFeature.cmake: -------------------------------------------------------------------------------- 1 | # This file defines the Feature Logging macros. 2 | # 3 | # MACRO_LOG_FEATURE(VAR FEATURE DESCRIPTION URL [REQUIRED [MIN_VERSION [COMMENTS]]]) 4 | # Logs the information so that it can be displayed at the end 5 | # of the configure run 6 | # VAR : TRUE or FALSE, indicating whether the feature is supported 7 | # FEATURE: name of the feature, e.g. "libjpeg" 8 | # DESCRIPTION: description what this feature provides 9 | # URL: home page 10 | # REQUIRED: TRUE or FALSE, indicating whether the featue is required 11 | # MIN_VERSION: minimum version number. empty string if unneeded 12 | # COMMENTS: More info you may want to provide. empty string if unnecessary 13 | # 14 | # MACRO_DISPLAY_FEATURE_LOG() 15 | # Call this to display the collected results. 16 | # Exits CMake with a FATAL error message if a required feature is missing 17 | # 18 | # Example: 19 | # 20 | # INCLUDE(MacroLogFeature) 21 | # 22 | # FIND_PACKAGE(JPEG) 23 | # MACRO_LOG_FEATURE(JPEG_FOUND "libjpeg" "Support JPEG images" "http://www.ijg.org" TRUE "3.2a" "") 24 | # ... 25 | # MACRO_DISPLAY_FEATURE_LOG() 26 | 27 | # Copyright (c) 2006, Alexander Neundorf, 28 | # Copyright (c) 2006, Allen Winter, 29 | # 30 | # Redistribution and use is allowed according to the terms of the BSD license. 31 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 32 | 33 | IF (NOT _macroLogFeatureAlreadyIncluded) 34 | SET(_file ${CMAKE_BINARY_DIR}/MissingRequirements.txt) 35 | IF (EXISTS ${_file}) 36 | FILE(REMOVE ${_file}) 37 | ENDIF (EXISTS ${_file}) 38 | 39 | SET(_file ${CMAKE_BINARY_DIR}/EnabledFeatures.txt) 40 | IF (EXISTS ${_file}) 41 | FILE(REMOVE ${_file}) 42 | ENDIF (EXISTS ${_file}) 43 | 44 | SET(_file ${CMAKE_BINARY_DIR}/DisabledFeatures.txt) 45 | IF (EXISTS ${_file}) 46 | FILE(REMOVE ${_file}) 47 | ENDIF (EXISTS ${_file}) 48 | 49 | SET(_macroLogFeatureAlreadyIncluded TRUE) 50 | ENDIF (NOT _macroLogFeatureAlreadyIncluded) 51 | 52 | 53 | MACRO(MACRO_LOG_FEATURE _var _package _description _url ) # _required _minvers _comments) 54 | 55 | SET(_required "${ARGV4}") 56 | SET(_minvers "${ARGV5}") 57 | SET(_comments "${ARGV6}") 58 | 59 | IF (${_var}) 60 | SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/EnabledFeatures.txt) 61 | ELSE (${_var}) 62 | IF (${_required} MATCHES "[Tt][Rr][Uu][Ee]") 63 | SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/MissingRequirements.txt) 64 | ELSE (${_required} MATCHES "[Tt][Rr][Uu][Ee]") 65 | SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/DisabledFeatures.txt) 66 | ENDIF (${_required} MATCHES "[Tt][Rr][Uu][Ee]") 67 | ENDIF (${_var}) 68 | 69 | SET(_logtext "+ ${_package}") 70 | 71 | IF (NOT ${_var}) 72 | IF (${_minvers} MATCHES ".*") 73 | SET(_logtext "${_logtext}, ${_minvers}") 74 | ENDIF (${_minvers} MATCHES ".*") 75 | SET(_logtext "${_logtext}: ${_description} <${_url}>") 76 | IF (${_comments} MATCHES ".*") 77 | SET(_logtext "${_logtext}\n${_comments}") 78 | ENDIF (${_comments} MATCHES ".*") 79 | # SET(_logtext "${_logtext}\n") #double-space missing features? 80 | ENDIF (NOT ${_var}) 81 | FILE(APPEND "${_LOGFILENAME}" "${_logtext}\n") 82 | 83 | ENDMACRO(MACRO_LOG_FEATURE) 84 | 85 | 86 | MACRO(MACRO_DISPLAY_FEATURE_LOG) 87 | 88 | SET(_file ${CMAKE_BINARY_DIR}/MissingRequirements.txt) 89 | IF (EXISTS ${_file}) 90 | FILE(READ ${_file} _requirements) 91 | MESSAGE(STATUS "\n-----------------------------------------------------------------------------\n-- The following REQUIRED packages could NOT be located on your system.\n-- Please install them before continuing this software installation.\n-----------------------------------------------------------------------------\n${_requirements}-----------------------------------------------------------------------------") 92 | FILE(REMOVE ${_file}) 93 | MESSAGE(FATAL_ERROR "Exiting: Missing Requirements") 94 | ENDIF (EXISTS ${_file}) 95 | 96 | SET(_summary "\n") 97 | 98 | SET(_elist 0) 99 | SET(_file ${CMAKE_BINARY_DIR}/EnabledFeatures.txt) 100 | IF (EXISTS ${_file}) 101 | SET(_elist 1) 102 | FILE(READ ${_file} _enabled) 103 | FILE(REMOVE ${_file}) 104 | SET(_summary "${_summary}-----------------------------------------------------------------------------\n-- The following external packages were located on your system.\n-- This installation will have the extra features provided by these packages.\n${_enabled}") 105 | ENDIF (EXISTS ${_file}) 106 | 107 | SET(_dlist 0) 108 | SET(_file ${CMAKE_BINARY_DIR}/DisabledFeatures.txt) 109 | IF (EXISTS ${_file}) 110 | SET(_dlist 1) 111 | FILE(READ ${_file} _disabled) 112 | FILE(REMOVE ${_file}) 113 | SET(_summary "${_summary}-----------------------------------------------------------------------------\n-- The following OPTIONAL packages could NOT be located on your system.\n-- Consider installing them to enable more features from this software.\n${_disabled}") 114 | ELSE (EXISTS ${_file}) 115 | IF (${_elist}) 116 | SET(_summary "${_summary}Congratulations! All external packages have been found.\n") 117 | ENDIF (${_elist}) 118 | ENDIF (EXISTS ${_file}) 119 | 120 | IF (${_elist} OR ${_dlist}) 121 | SET(_summary "${_summary}-----------------------------------------------------------------------------\n") 122 | ENDIF (${_elist} OR ${_dlist}) 123 | MESSAGE(STATUS "${_summary}") 124 | 125 | ENDMACRO(MACRO_DISPLAY_FEATURE_LOG) 126 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cloudrainmonitor.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Copyright(c) 2016 Derek OKeeffe. All rights reserved. 3 | 4 | INDI driver for a Cloud and rain monitor for an astronomical observatory. 5 | The device hardware is arduino based and provides an HTTP api. 6 | Example GET request to http://192.168.1.204/weather 7 | Returns a 200 response like below 8 | { 9 | "uptime":"05:14:12", 10 | "skyTemp": 4.230, 11 | "outsideTemp": 10.090, 12 | "rain":false 13 | } 14 | 15 | This driver is responsible for providing weather state information to INDI clients. 16 | The INDI client will decide what action to take (for example: initiate an observatory shutdown or startup process). 17 | 18 | This program is free software; you can redistribute it and/or modify it 19 | under the terms of the GNU General Public License as published by the Free 20 | Software Foundation; either version 2 of the License, or (at your option) 21 | any later version. 22 | 23 | This program is distributed in the hope that it will be useful, but WITHOUT 24 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 25 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 26 | more details. 27 | 28 | You should have received a copy of the GNU Library General Public License 29 | along with this library; see the file COPYING.LIB. If not, write to 30 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 31 | Boston, MA 02110-1301, USA. 32 | 33 | The full GNU General Public License is included in this distribution in the 34 | file called LICENSE. 35 | *******************************************************************************/ 36 | 37 | #include 38 | #include "cloudrainmonitor.h" 39 | #include "gason.h" 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include 48 | 49 | std::unique_ptr indicloudrainmonitor(new IndiCloudRainMonitor()); 50 | 51 | static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) 52 | { 53 | ((std::string*)userp)->append((char*)contents, size * nmemb); 54 | return size * nmemb; 55 | } 56 | 57 | void ISGetProperties(const char *dev) 58 | { 59 | indicloudrainmonitor->ISGetProperties(dev); 60 | } 61 | 62 | void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) 63 | { 64 | indicloudrainmonitor->ISNewSwitch(dev, name, states, names, num); 65 | } 66 | 67 | void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) 68 | { 69 | indicloudrainmonitor->ISNewText(dev, name, texts, names, num); 70 | } 71 | 72 | void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) 73 | { 74 | indicloudrainmonitor->ISNewNumber(dev, name, values, names, num); 75 | } 76 | 77 | void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) 78 | { 79 | INDI_UNUSED(dev); 80 | INDI_UNUSED(name); 81 | INDI_UNUSED(sizes); 82 | INDI_UNUSED(blobsizes); 83 | INDI_UNUSED(blobs); 84 | INDI_UNUSED(formats); 85 | INDI_UNUSED(names); 86 | INDI_UNUSED(n); 87 | } 88 | void ISSnoopDevice (XMLEle *root) 89 | { 90 | indicloudrainmonitor->ISSnoopDevice(root); 91 | } 92 | 93 | IndiCloudRainMonitor::IndiCloudRainMonitor() 94 | { 95 | setVersion(1,0); 96 | } 97 | 98 | IndiCloudRainMonitor::~IndiCloudRainMonitor() 99 | { 100 | 101 | } 102 | 103 | const char * IndiCloudRainMonitor::getDefaultName() 104 | { 105 | return (char *)"Indi Cloud Rain Monitor"; 106 | } 107 | 108 | bool IndiCloudRainMonitor::Connect() 109 | { 110 | DEBUG(INDI::Logger::DBG_SESSION, "CONNECTING."); 111 | if (httpEndpointT[0].text == NULL) 112 | { 113 | DEBUG(INDI::Logger::DBG_ERROR, "cloudrainmonitor HTTP API endpoint is not available. Set it in the options tab"); 114 | return false; 115 | } 116 | 117 | CURL *curl; 118 | CURLcode res; 119 | std::string readBuffer; 120 | 121 | curl = curl_easy_init(); 122 | if(curl) { 123 | curl_easy_setopt(curl, CURLOPT_URL, httpEndpointT[0].text); 124 | curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); //10 sec timeout 125 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); 126 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); 127 | res = curl_easy_perform(curl); 128 | /* Check for errors */ 129 | if(res != CURLE_OK) { 130 | DEBUG(INDI::Logger::DBG_ERROR, "Connecttion to HTTP endpoint failed"); 131 | DEBUG(INDI::Logger::DBG_ERROR, "Is the HTTP API endpoint correct? Set it in the options tab. Can you ping the weather device?"); 132 | return false; 133 | } 134 | /* always cleanup */ 135 | curl_easy_cleanup(curl); 136 | 137 | char srcBuffer[readBuffer.size()]; 138 | strncpy(srcBuffer, readBuffer.c_str(), readBuffer.size()); 139 | char *source = srcBuffer; 140 | // do not forget terminate source string with 0 141 | char *endptr; 142 | JsonValue value; 143 | JsonAllocator allocator; 144 | int status = jsonParse(source, &endptr, &value, allocator); 145 | if (status != JSON_OK) 146 | { 147 | DEBUGF(INDI::Logger::DBG_ERROR, "%s at %zd", jsonStrError(status), endptr - source); 148 | DEBUGF(INDI::Logger::DBG_DEBUG, "%s", readBuffer.c_str()); 149 | return IPS_ALERT; 150 | } 151 | DEBUGF(INDI::Logger::DBG_DEBUG, "HTTP response %s", readBuffer.c_str()); 152 | JsonIterator it; 153 | for (it = begin(value); it!= end(value); ++it) { 154 | DEBUGF(INDI::Logger::DBG_DEBUG, "iterating %s", it->key); 155 | } 156 | } 157 | 158 | return true; 159 | } 160 | 161 | bool IndiCloudRainMonitor::Disconnect() 162 | { 163 | return true; 164 | } 165 | 166 | bool IndiCloudRainMonitor::initProperties() 167 | { 168 | INDI::Weather::initProperties(); 169 | 170 | IUFillText(&httpEndpointT[0], "API_ENDPOINT", "API Endpoint", "http://192.168.1.204/weather"); //this is the default but can be changed in the options OPTIONS_TAB. 171 | IUFillTextVector(&httpEndpointTP, httpEndpointT, 1, getDeviceName(), "HTTP_API_ENDPOINT", "HTTP endpoint", OPTIONS_TAB, IP_RW, 5, IPS_IDLE); 172 | 173 | addParameter("WEATHER_RAIN", "Rain", 0, 0, 0); 174 | setCriticalParameter("WEATHER_RAIN"); 175 | addParameter("WEATHER_STATION_ONLINE", "Station Online", 0, 0, 0); 176 | setCriticalParameter("WEATHER_STATION_ONLINE"); 177 | addParameter("WEATHER_CLOUD_COVER", "Cloud Cover", 0, 0, 0); 178 | setCriticalParameter("WEATHER_CLOUD_COVER"); 179 | 180 | addDebugControl(); 181 | return true; 182 | } 183 | 184 | void IndiCloudRainMonitor::ISGetProperties(const char *dev) 185 | { 186 | INDI::Weather::ISGetProperties(dev); 187 | 188 | defineProperty(&httpEndpointTP); 189 | loadConfig(true, "HTTP_API_ENDPOINT"); 190 | } 191 | 192 | bool IndiCloudRainMonitor::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) 193 | { 194 | if(!strcmp(dev,getDeviceName())) 195 | { 196 | if (!strcmp(httpEndpointTP.name, name)) 197 | { 198 | IUUpdateText(&httpEndpointTP, texts, names, n); 199 | httpEndpointTP.s = IPS_OK; 200 | IDSetText(&httpEndpointTP, NULL); 201 | return true; 202 | } 203 | 204 | } 205 | 206 | return INDI::Weather::ISNewText(dev,name,texts,names,n); 207 | } 208 | 209 | /** 210 | * Poll the device's HTTP API to get the latest measurements. Set the state based on these measurements. 211 | */ 212 | IPState IndiCloudRainMonitor::updateWeather() 213 | { 214 | DEBUG(INDI::Logger::DBG_DEBUG, "Updating from weather API_ENDPOINT"); 215 | CURL *curl; 216 | CURLcode res; 217 | std::string readBuffer; 218 | 219 | curl = curl_easy_init(); 220 | if(curl) { 221 | curl_easy_setopt(curl, CURLOPT_URL, httpEndpointT[0].text); 222 | curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); //10 sec timeout 223 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); 224 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); 225 | res = curl_easy_perform(curl); 226 | /* Check for errors */ 227 | 228 | DEBUG(INDI::Logger::DBG_DEBUG, "curl complete"); 229 | 230 | if(res != CURLE_OK) { 231 | DEBUG(INDI::Logger::DBG_ERROR, "curl failed!!!!!!"); 232 | // DEBUGF(INDI::Logger::DBG_ERROR, "Connecttion to HTTP_API_ENDPOINT failed:%s",curl_easy_strerror(res)); 233 | DEBUG(INDI::Logger::DBG_ERROR, "Cant contact weather device setting alert state"); 234 | setParameterValue("WEATHER_STATION_ONLINE", 1); 235 | return IPS_OK; 236 | } 237 | DEBUG(INDI::Logger::DBG_DEBUG, "curl ok"); 238 | 239 | /* always cleanup */ 240 | curl_easy_cleanup(curl); 241 | 242 | char srcBuffer[readBuffer.size()]; 243 | strncpy(srcBuffer, readBuffer.c_str(), readBuffer.size()); 244 | char *source = srcBuffer; 245 | // do not forget terminate source string with 0 246 | char *endptr; 247 | JsonValue value; 248 | JsonAllocator allocator; 249 | int status = jsonParse(source, &endptr, &value, allocator); 250 | if (status != JSON_OK) 251 | { 252 | DEBUG(INDI::Logger::DBG_ERROR, "NON OK response, setting alert state"); 253 | setParameterValue("WEATHER_STATION_ONLINE", 1); 254 | return IPS_OK; 255 | } 256 | DEBUGF(INDI::Logger::DBG_DEBUG, "http response %s", readBuffer.c_str()); 257 | JsonIterator it; 258 | double skyTemp; 259 | double ambientTemp; 260 | for (it = begin(value); it!= end(value); ++it) { 261 | LOGF_DEBUG("iterating %s", it->key); 262 | if (!strcmp(it->key, "rain")) { 263 | //bool raining = it->value.toBool(); 264 | //DEBUGF(INDI::Logger::DBG_DEBUG, "Setting rain value from response %s", it->value); 265 | if (it->value.getTag()==JSON_TRUE) { 266 | setParameterValue("WEATHER_RAIN", 1); 267 | } else { 268 | setParameterValue("WEATHER_RAIN", 0); 269 | } 270 | } 271 | if (!strcmp(it->key, "skyTemp")) { 272 | LOGF_DEBUG("Got skyTemp from response %g", it->value.toNumber()); 273 | skyTemp = it->value.toNumber(); 274 | } 275 | if (!strcmp(it->key, "outsideTemp")) { 276 | LOGF_DEBUG("Got outsideTemp from response %g", it->value.toNumber()); 277 | ambientTemp = it->value.toNumber(); 278 | } 279 | } 280 | //Function based on data collected, guesswork and linear regression using wolframalpha https://www.wolframalpha.com/input/?i=linear+fit+{0,+100},{-1,+90},{-2,+80},{-3,+50},{-4,+25},{-5,+10},{-6,0}&lk=3 281 | double result = (18 * skyTemp) + 100; 282 | if(result > 100) { 283 | result = 100; 284 | } 285 | if(result < 0) { 286 | result = 0; 287 | } 288 | LOGF_DEBUG("CLOUD %g", result); 289 | setParameterValue("WEATHER_CLOUD_COVER", result); 290 | } 291 | setParameterValue("WEATHER_STATION_ONLINE", 0); 292 | return IPS_OK; 293 | } 294 | 295 | bool IndiCloudRainMonitor::saveConfigItems(FILE *fp) 296 | { 297 | INDI::Weather::saveConfigItems(fp); 298 | 299 | IUSaveConfigText(fp, &httpEndpointTP); 300 | 301 | return true; 302 | } 303 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/gason.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2013-2015 Ivan Vashchaev 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include "gason.h" 25 | #include 26 | 27 | #define JSON_ZONE_SIZE 4096 28 | #define JSON_STACK_SIZE 32 29 | 30 | const char *jsonStrError(int err) { 31 | switch (err) { 32 | #define XX(no, str) \ 33 | case JSON_##no: \ 34 | return str; 35 | JSON_ERRNO_MAP(XX) 36 | #undef XX 37 | default: 38 | return "unknown"; 39 | } 40 | } 41 | 42 | void *JsonAllocator::allocate(size_t size) { 43 | size = (size + 7) & ~7; 44 | 45 | if (head && head->used + size <= JSON_ZONE_SIZE) { 46 | char *p = (char *)head + head->used; 47 | head->used += size; 48 | return p; 49 | } 50 | 51 | size_t allocSize = sizeof(Zone) + size; 52 | Zone *zone = (Zone *)malloc(allocSize <= JSON_ZONE_SIZE ? JSON_ZONE_SIZE : allocSize); 53 | if (zone == nullptr) 54 | return nullptr; 55 | zone->used = allocSize; 56 | if (allocSize <= JSON_ZONE_SIZE || head == nullptr) { 57 | zone->next = head; 58 | head = zone; 59 | } else { 60 | zone->next = head->next; 61 | head->next = zone; 62 | } 63 | return (char *)zone + sizeof(Zone); 64 | } 65 | 66 | void JsonAllocator::deallocate() { 67 | while (head) { 68 | Zone *next = head->next; 69 | free(head); 70 | head = next; 71 | } 72 | } 73 | 74 | static inline bool isspace(char c) { 75 | return c == ' ' || (c >= '\t' && c <= '\r'); 76 | } 77 | 78 | static inline bool isdelim(char c) { 79 | return c == ',' || c == ':' || c == ']' || c == '}' || isspace(c) || !c; 80 | } 81 | 82 | static inline bool isdigit(char c) { 83 | return c >= '0' && c <= '9'; 84 | } 85 | 86 | static inline bool isxdigit(char c) { 87 | return (c >= '0' && c <= '9') || ((c & ~' ') >= 'A' && (c & ~' ') <= 'F'); 88 | } 89 | 90 | static inline int char2int(char c) { 91 | if (c <= '9') 92 | return c - '0'; 93 | return (c & ~' ') - 'A' + 10; 94 | } 95 | 96 | static double string2double(char *s, char **endptr) { 97 | char ch = *s; 98 | if (ch == '-') 99 | ++s; 100 | 101 | double result = 0; 102 | while (isdigit(*s)) 103 | result = (result * 10) + (*s++ - '0'); 104 | 105 | if (*s == '.') { 106 | ++s; 107 | 108 | double fraction = 1; 109 | while (isdigit(*s)) { 110 | fraction *= 0.1; 111 | result += (*s++ - '0') * fraction; 112 | } 113 | } 114 | 115 | if (*s == 'e' || *s == 'E') { 116 | ++s; 117 | 118 | double base = 10; 119 | if (*s == '+') 120 | ++s; 121 | else if (*s == '-') { 122 | ++s; 123 | base = 0.1; 124 | } 125 | 126 | unsigned int exponent = 0; 127 | while (isdigit(*s)) 128 | exponent = (exponent * 10) + (*s++ - '0'); 129 | 130 | double power = 1; 131 | for (; exponent; exponent >>= 1, base *= base) 132 | if (exponent & 1) 133 | power *= base; 134 | 135 | result *= power; 136 | } 137 | 138 | *endptr = s; 139 | return ch == '-' ? -result : result; 140 | } 141 | 142 | static inline JsonNode *insertAfter(JsonNode *tail, JsonNode *node) { 143 | if (!tail) 144 | return node->next = node; 145 | node->next = tail->next; 146 | tail->next = node; 147 | return node; 148 | } 149 | 150 | static inline JsonValue listToValue(JsonTag tag, JsonNode *tail) { 151 | if (tail) { 152 | auto head = tail->next; 153 | tail->next = nullptr; 154 | return JsonValue(tag, head); 155 | } 156 | return JsonValue(tag, nullptr); 157 | } 158 | 159 | int jsonParse(char *s, char **endptr, JsonValue *value, JsonAllocator &allocator) { 160 | JsonNode *tails[JSON_STACK_SIZE]; 161 | JsonTag tags[JSON_STACK_SIZE]; 162 | char *keys[JSON_STACK_SIZE]; 163 | JsonValue o; 164 | int pos = -1; 165 | bool separator = true; 166 | JsonNode *node; 167 | *endptr = s; 168 | 169 | while (*s) { 170 | while (isspace(*s)) { 171 | ++s; 172 | if (!*s) break; 173 | } 174 | *endptr = s++; 175 | switch (**endptr) { 176 | case '-': 177 | if (!isdigit(*s) && *s != '.') { 178 | *endptr = s; 179 | return JSON_BAD_NUMBER; 180 | } 181 | case '0': 182 | case '1': 183 | case '2': 184 | case '3': 185 | case '4': 186 | case '5': 187 | case '6': 188 | case '7': 189 | case '8': 190 | case '9': 191 | o = JsonValue(string2double(*endptr, &s)); 192 | if (!isdelim(*s)) { 193 | *endptr = s; 194 | return JSON_BAD_NUMBER; 195 | } 196 | break; 197 | case '"': 198 | o = JsonValue(JSON_STRING, s); 199 | for (char *it = s; *s; ++it, ++s) { 200 | int c = *it = *s; 201 | if (c == '\\') { 202 | c = *++s; 203 | switch (c) { 204 | case '\\': 205 | case '"': 206 | case '/': 207 | *it = c; 208 | break; 209 | case 'b': 210 | *it = '\b'; 211 | break; 212 | case 'f': 213 | *it = '\f'; 214 | break; 215 | case 'n': 216 | *it = '\n'; 217 | break; 218 | case 'r': 219 | *it = '\r'; 220 | break; 221 | case 't': 222 | *it = '\t'; 223 | break; 224 | case 'u': 225 | c = 0; 226 | for (int i = 0; i < 4; ++i) { 227 | if (isxdigit(*++s)) { 228 | c = c * 16 + char2int(*s); 229 | } else { 230 | *endptr = s; 231 | return JSON_BAD_STRING; 232 | } 233 | } 234 | if (c < 0x80) { 235 | *it = c; 236 | } else if (c < 0x800) { 237 | *it++ = 0xC0 | (c >> 6); 238 | *it = 0x80 | (c & 0x3F); 239 | } else { 240 | *it++ = 0xE0 | (c >> 12); 241 | *it++ = 0x80 | ((c >> 6) & 0x3F); 242 | *it = 0x80 | (c & 0x3F); 243 | } 244 | break; 245 | default: 246 | *endptr = s; 247 | return JSON_BAD_STRING; 248 | } 249 | } else if ((unsigned int)c < ' ' || c == '\x7F') { 250 | *endptr = s; 251 | return JSON_BAD_STRING; 252 | } else if (c == '"') { 253 | *it = 0; 254 | ++s; 255 | break; 256 | } 257 | } 258 | if (!isdelim(*s)) { 259 | *endptr = s; 260 | return JSON_BAD_STRING; 261 | } 262 | break; 263 | case 't': 264 | if (!(s[0] == 'r' && s[1] == 'u' && s[2] == 'e' && isdelim(s[3]))) 265 | return JSON_BAD_IDENTIFIER; 266 | o = JsonValue(JSON_TRUE); 267 | s += 3; 268 | break; 269 | case 'f': 270 | if (!(s[0] == 'a' && s[1] == 'l' && s[2] == 's' && s[3] == 'e' && isdelim(s[4]))) 271 | return JSON_BAD_IDENTIFIER; 272 | o = JsonValue(JSON_FALSE); 273 | s += 4; 274 | break; 275 | case 'n': 276 | if (!(s[0] == 'u' && s[1] == 'l' && s[2] == 'l' && isdelim(s[3]))) 277 | return JSON_BAD_IDENTIFIER; 278 | o = JsonValue(JSON_NULL); 279 | s += 3; 280 | break; 281 | case ']': 282 | if (pos == -1) 283 | return JSON_STACK_UNDERFLOW; 284 | if (tags[pos] != JSON_ARRAY) 285 | return JSON_MISMATCH_BRACKET; 286 | o = listToValue(JSON_ARRAY, tails[pos--]); 287 | break; 288 | case '}': 289 | if (pos == -1) 290 | return JSON_STACK_UNDERFLOW; 291 | if (tags[pos] != JSON_OBJECT) 292 | return JSON_MISMATCH_BRACKET; 293 | if (keys[pos] != nullptr) 294 | return JSON_UNEXPECTED_CHARACTER; 295 | o = listToValue(JSON_OBJECT, tails[pos--]); 296 | break; 297 | case '[': 298 | if (++pos == JSON_STACK_SIZE) 299 | return JSON_STACK_OVERFLOW; 300 | tails[pos] = nullptr; 301 | tags[pos] = JSON_ARRAY; 302 | keys[pos] = nullptr; 303 | separator = true; 304 | continue; 305 | case '{': 306 | if (++pos == JSON_STACK_SIZE) 307 | return JSON_STACK_OVERFLOW; 308 | tails[pos] = nullptr; 309 | tags[pos] = JSON_OBJECT; 310 | keys[pos] = nullptr; 311 | separator = true; 312 | continue; 313 | case ':': 314 | if (separator || keys[pos] == nullptr) 315 | return JSON_UNEXPECTED_CHARACTER; 316 | separator = true; 317 | continue; 318 | case ',': 319 | if (separator || keys[pos] != nullptr) 320 | return JSON_UNEXPECTED_CHARACTER; 321 | separator = true; 322 | continue; 323 | case '\0': 324 | continue; 325 | default: 326 | return JSON_UNEXPECTED_CHARACTER; 327 | } 328 | 329 | separator = false; 330 | 331 | if (pos == -1) { 332 | *endptr = s; 333 | *value = o; 334 | return JSON_OK; 335 | } 336 | 337 | if (tags[pos] == JSON_OBJECT) { 338 | if (!keys[pos]) { 339 | if (o.getTag() != JSON_STRING) 340 | return JSON_UNQUOTED_KEY; 341 | keys[pos] = o.toString(); 342 | continue; 343 | } 344 | if ((node = (JsonNode *) allocator.allocate(sizeof(JsonNode))) == nullptr) 345 | return JSON_ALLOCATION_FAILURE; 346 | tails[pos] = insertAfter(tails[pos], node); 347 | tails[pos]->key = keys[pos]; 348 | keys[pos] = nullptr; 349 | } else { 350 | if ((node = (JsonNode *) allocator.allocate(sizeof(JsonNode) - sizeof(char *))) == nullptr) 351 | return JSON_ALLOCATION_FAILURE; 352 | tails[pos] = insertAfter(tails[pos], node); 353 | } 354 | tails[pos]->value = o; 355 | } 356 | return JSON_BREAKING_BAD; 357 | } 358 | -------------------------------------------------------------------------------- /indi-driver/cloud-rain-monitor/cmake_modules/FindINDI.cmake: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); 2 | # you may not use this file except in compliance with the License. 3 | # You may obtain a copy of the License at 4 | # http://www.apache.org/licenses/LICENSE-2.0 5 | # Unless required by applicable law or agreed to in writing, software 6 | # distributed under the License is distributed on an "AS IS" BASIS, 7 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8 | # See the License for the specific language governing permissions and 9 | # limitations under the License. 10 | # 11 | # This module can find INDI Library 12 | # 13 | # Requirements: 14 | # - CMake >= 2.8.3 (for new version of find_package_handle_standard_args) 15 | # 16 | # The following variables will be defined for your use: 17 | # - INDI_FOUND : were all of your specified components found (include dependencies)? 18 | # - INDI_INCLUDE_DIR : INDI include directory 19 | # - INDI_DATA_DIR : INDI include directory 20 | # - INDI_LIBRARIES : INDI libraries 21 | # - INDI_DRIVER_LIBRARIES : Same as above maintained for backward compatibility 22 | # - INDI_VERSION : complete version of INDI (x.y.z) 23 | # - INDI_MAJOR_VERSION : major version of INDI 24 | # - INDI_MINOR_VERSION : minor version of INDI 25 | # - INDI_RELEASE_VERSION : release version of INDI 26 | # - INDI__FOUND : were found? (FALSE for non specified component if it is not a dependency) 27 | # 28 | # For windows or non standard installation, define INDI_ROOT variable to point to the root installation of INDI. Two ways: 29 | # - run cmake with -DINDI_ROOT= 30 | # - define an environment variable with the same name before running cmake 31 | # With cmake-gui, before pressing "Configure": 32 | # 1) Press "Add Entry" button 33 | # 2) Add a new entry defined as: 34 | # - Name: INDI_ROOT 35 | # - Type: choose PATH in the selection list 36 | # - Press "..." button and select the root installation of INDI 37 | # 38 | # Example Usage: 39 | # 40 | # 1. Copy this file in the root of your project source directory 41 | # 2. Then, tell CMake to search this non-standard module in your project directory by adding to your CMakeLists.txt: 42 | # set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}) 43 | # 3. Finally call find_package() once, here are some examples to pick from 44 | # 45 | # Require INDI 1.4 or later 46 | # find_package(INDI 1.4 REQUIRED) 47 | # 48 | # if(INDI_FOUND) 49 | # include_directories(${INDI_INCLUDE_DIR}) 50 | # add_executable(myapp myapp.cpp) 51 | # target_link_libraries(myapp ${INDI_LIBRARIES}) 52 | # endif(INDI_FOUND) 53 | # 54 | # 55 | # Using Components: 56 | # 57 | # You can search for specific components. Currently, the following components are available 58 | # * driver 59 | # * align 60 | # * client 61 | # * clientqt5 62 | # 63 | # By default, if you do not specify any components, driver and align components are searched. 64 | # 65 | # Example: 66 | # 67 | # To use INDI Qt5 Client library only in your application: 68 | # 69 | # find_package(INDI CLIENTQT5 REQUIRED) 70 | # 71 | # if(INDI_FOUND) 72 | # include_directories(${INDI_INCLUDE_DIR}) 73 | # add_executable(myapp myapp.cpp) 74 | # target_link_libraries(myapp ${INDI_CLIENTQT5_LIBRARIES}) 75 | # endif(INDI_FOUND) 76 | # 77 | #============================================================================= 78 | # Copyright (c) 2011-2013, julp 79 | # Copyright (c) 2017 Jasem Mutlaq 80 | # 81 | # Distributed under the OSI-approved BSD License 82 | # 83 | # This software is distributed WITHOUT ANY WARRANTY; without even the 84 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTINDILAR PURPOSE. 85 | #============================================================================= 86 | 87 | find_package(PkgConfig QUIET) 88 | 89 | ########## Private ########## 90 | if(NOT DEFINED INDI_PUBLIC_VAR_NS) 91 | set(INDI_PUBLIC_VAR_NS "INDI") # Prefix for all INDI relative public variables 92 | endif(NOT DEFINED INDI_PUBLIC_VAR_NS) 93 | if(NOT DEFINED INDI_PRIVATE_VAR_NS) 94 | set(INDI_PRIVATE_VAR_NS "_${INDI_PUBLIC_VAR_NS}") # Prefix for all INDI relative internal variables 95 | endif(NOT DEFINED INDI_PRIVATE_VAR_NS) 96 | if(NOT DEFINED PC_INDI_PRIVATE_VAR_NS) 97 | set(PC_INDI_PRIVATE_VAR_NS "_PC${INDI_PRIVATE_VAR_NS}") # Prefix for all pkg-config relative internal variables 98 | endif(NOT DEFINED PC_INDI_PRIVATE_VAR_NS) 99 | 100 | function(indidebug _VARNAME) 101 | if(${INDI_PUBLIC_VAR_NS}_DEBUG) 102 | if(DEFINED ${INDI_PUBLIC_VAR_NS}_${_VARNAME}) 103 | message("${INDI_PUBLIC_VAR_NS}_${_VARNAME} = ${${INDI_PUBLIC_VAR_NS}_${_VARNAME}}") 104 | else(DEFINED ${INDI_PUBLIC_VAR_NS}_${_VARNAME}) 105 | message("${INDI_PUBLIC_VAR_NS}_${_VARNAME} = ") 106 | endif(DEFINED ${INDI_PUBLIC_VAR_NS}_${_VARNAME}) 107 | endif(${INDI_PUBLIC_VAR_NS}_DEBUG) 108 | endfunction(indidebug) 109 | 110 | set(${INDI_PRIVATE_VAR_NS}_ROOT "") 111 | if(DEFINED ENV{INDI_ROOT}) 112 | set(${INDI_PRIVATE_VAR_NS}_ROOT "$ENV{INDI_ROOT}") 113 | endif(DEFINED ENV{INDI_ROOT}) 114 | if (DEFINED INDI_ROOT) 115 | set(${INDI_PRIVATE_VAR_NS}_ROOT "${INDI_ROOT}") 116 | endif(DEFINED INDI_ROOT) 117 | 118 | set(${INDI_PRIVATE_VAR_NS}_BIN_SUFFIXES ) 119 | set(${INDI_PRIVATE_VAR_NS}_LIB_SUFFIXES ) 120 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 121 | list(APPEND ${INDI_PRIVATE_VAR_NS}_BIN_SUFFIXES "bin64") 122 | list(APPEND ${INDI_PRIVATE_VAR_NS}_LIB_SUFFIXES "lib64") 123 | endif(CMAKE_SIZEOF_VOID_P EQUAL 8) 124 | list(APPEND ${INDI_PRIVATE_VAR_NS}_BIN_SUFFIXES "bin") 125 | list(APPEND ${INDI_PRIVATE_VAR_NS}_LIB_SUFFIXES "lib") 126 | 127 | set(${INDI_PRIVATE_VAR_NS}_COMPONENTS ) 128 | # ... 129 | macro(INDI_declare_component _NAME) 130 | list(APPEND ${INDI_PRIVATE_VAR_NS}_COMPONENTS ${_NAME}) 131 | set("${INDI_PRIVATE_VAR_NS}_COMPONENTS_${_NAME}" ${ARGN}) 132 | endmacro(INDI_declare_component) 133 | 134 | INDI_declare_component(driver indidriver) 135 | INDI_declare_component(align indiAlignmentDriver) 136 | INDI_declare_component(client indiclient) 137 | INDI_declare_component(clientqt5 indiclientqt5) 138 | 139 | ########## Public ########## 140 | set(${INDI_PUBLIC_VAR_NS}_FOUND TRUE) 141 | set(${INDI_PUBLIC_VAR_NS}_LIBRARIES ) 142 | set(${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR ) 143 | foreach(${INDI_PRIVATE_VAR_NS}_COMPONENT ${${INDI_PRIVATE_VAR_NS}_COMPONENTS}) 144 | string(TOUPPER "${${INDI_PRIVATE_VAR_NS}_COMPONENT}" ${INDI_PRIVATE_VAR_NS}_UPPER_COMPONENT) 145 | set("${INDI_PUBLIC_VAR_NS}_${${INDI_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" FALSE) # may be done in the INDI_declare_component macro 146 | endforeach(${INDI_PRIVATE_VAR_NS}_COMPONENT) 147 | 148 | # Check components 149 | if(NOT ${INDI_PUBLIC_VAR_NS}_FIND_COMPONENTS) # driver and posix client by default 150 | set(${INDI_PUBLIC_VAR_NS}_FIND_COMPONENTS driver align) 151 | else(NOT ${INDI_PUBLIC_VAR_NS}_FIND_COMPONENTS) 152 | #list(APPEND ${INDI_PUBLIC_VAR_NS}_FIND_COMPONENTS uc) 153 | list(REMOVE_DUPLICATES ${INDI_PUBLIC_VAR_NS}_FIND_COMPONENTS) 154 | foreach(${INDI_PRIVATE_VAR_NS}_COMPONENT ${${INDI_PUBLIC_VAR_NS}_FIND_COMPONENTS}) 155 | if(NOT DEFINED ${INDI_PRIVATE_VAR_NS}_COMPONENTS_${${INDI_PRIVATE_VAR_NS}_COMPONENT}) 156 | message(FATAL_ERROR "Unknown INDI component: ${${INDI_PRIVATE_VAR_NS}_COMPONENT}") 157 | endif(NOT DEFINED ${INDI_PRIVATE_VAR_NS}_COMPONENTS_${${INDI_PRIVATE_VAR_NS}_COMPONENT}) 158 | endforeach(${INDI_PRIVATE_VAR_NS}_COMPONENT) 159 | endif(NOT ${INDI_PUBLIC_VAR_NS}_FIND_COMPONENTS) 160 | 161 | # Includes 162 | find_path( 163 | ${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR 164 | indidevapi.h 165 | PATH_SUFFIXES libindi 166 | ${PC_INDI_INCLUDE_DIR} 167 | ${_obIncDir} 168 | ${GNUWIN32_DIR}/include 169 | HINTS ${${INDI_PRIVATE_VAR_NS}_ROOT} 170 | DOC "Include directory for INDI" 171 | ) 172 | 173 | find_path(${INDI_PUBLIC_VAR_NS}_DATA_DIR 174 | drivers.xml 175 | PATH_SUFFIXES share/indi 176 | DOC "Data directory for INDI" 177 | ) 178 | 179 | if(${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR) 180 | if(EXISTS "${${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR}/indiversion.h") # INDI >= 1.4 181 | file(READ "${${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR}/indiversion.h" ${INDI_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS) 182 | else() 183 | message(FATAL_ERROR "INDI version header not found") 184 | endif() 185 | 186 | if(${INDI_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS MATCHES ".*INDI_VERSION ([0-9]+).([0-9]+).([0-9]+)") 187 | set(${INDI_PUBLIC_VAR_NS}_MAJOR_VERSION "${CMAKE_MATCH_1}") 188 | set(${INDI_PUBLIC_VAR_NS}_MINOR_VERSION "${CMAKE_MATCH_2}") 189 | set(${INDI_PUBLIC_VAR_NS}_RELEASE_VERSION "${CMAKE_MATCH_3}") 190 | else() 191 | message(FATAL_ERROR "failed to detect INDI version") 192 | endif() 193 | set(${INDI_PUBLIC_VAR_NS}_VERSION "${${INDI_PUBLIC_VAR_NS}_MAJOR_VERSION}.${${INDI_PUBLIC_VAR_NS}_MINOR_VERSION}.${${INDI_PUBLIC_VAR_NS}_RELEASE_VERSION}") 194 | 195 | # Check libraries 196 | foreach(${INDI_PRIVATE_VAR_NS}_COMPONENT ${${INDI_PUBLIC_VAR_NS}_FIND_COMPONENTS}) 197 | set(${INDI_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES ) 198 | set(${INDI_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES ) 199 | foreach(${INDI_PRIVATE_VAR_NS}_BASE_NAME ${${INDI_PRIVATE_VAR_NS}_COMPONENTS_${${INDI_PRIVATE_VAR_NS}_COMPONENT}}) 200 | list(APPEND ${INDI_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES "${${INDI_PRIVATE_VAR_NS}_BASE_NAME}") 201 | list(APPEND ${INDI_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES "${${INDI_PRIVATE_VAR_NS}_BASE_NAME}d") 202 | list(APPEND ${INDI_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES "${${INDI_PRIVATE_VAR_NS}_BASE_NAME}${INDI_MAJOR_VERSION}${INDI_MINOR_VERSION}") 203 | list(APPEND ${INDI_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES "${${INDI_PRIVATE_VAR_NS}_BASE_NAME}${INDI_MAJOR_VERSION}${INDI_MINOR_VERSION}d") 204 | endforeach(${INDI_PRIVATE_VAR_NS}_BASE_NAME) 205 | 206 | find_library( 207 | ${INDI_PRIVATE_VAR_NS}_LIB_RELEASE_${${INDI_PRIVATE_VAR_NS}_COMPONENT} 208 | NAMES ${${INDI_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES} 209 | HINTS ${${INDI_PRIVATE_VAR_NS}_ROOT} 210 | PATH_SUFFIXES ${_INDI_LIB_SUFFIXES} 211 | DOC "Release libraries for INDI" 212 | ) 213 | find_library( 214 | ${INDI_PRIVATE_VAR_NS}_LIB_DEBUG_${${INDI_PRIVATE_VAR_NS}_COMPONENT} 215 | NAMES ${${INDI_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES} 216 | HINTS ${${INDI_PRIVATE_VAR_NS}_ROOT} 217 | PATH_SUFFIXES ${_INDI_LIB_SUFFIXES} 218 | DOC "Debug libraries for INDI" 219 | ) 220 | 221 | string(TOUPPER "${${INDI_PRIVATE_VAR_NS}_COMPONENT}" ${INDI_PRIVATE_VAR_NS}_UPPER_COMPONENT) 222 | if(NOT ${INDI_PRIVATE_VAR_NS}_LIB_RELEASE_${${INDI_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${INDI_PRIVATE_VAR_NS}_LIB_DEBUG_${${INDI_PRIVATE_VAR_NS}_COMPONENT}) # both not found 223 | set("${INDI_PUBLIC_VAR_NS}_${${INDI_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" FALSE) 224 | set("${INDI_PUBLIC_VAR_NS}_FOUND" FALSE) 225 | else(NOT ${INDI_PRIVATE_VAR_NS}_LIB_RELEASE_${${INDI_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${INDI_PRIVATE_VAR_NS}_LIB_DEBUG_${${INDI_PRIVATE_VAR_NS}_COMPONENT}) # one or both found 226 | set("${INDI_PUBLIC_VAR_NS}_${${INDI_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" TRUE) 227 | if(NOT ${INDI_PRIVATE_VAR_NS}_LIB_RELEASE_${${INDI_PRIVATE_VAR_NS}_COMPONENT}) # release not found => we are in debug 228 | set(${INDI_PRIVATE_VAR_NS}_LIB_${${INDI_PRIVATE_VAR_NS}_COMPONENT} "${${INDI_PRIVATE_VAR_NS}_LIB_DEBUG_${${INDI_PRIVATE_VAR_NS}_COMPONENT}}") 229 | elseif(NOT ${INDI_PRIVATE_VAR_NS}_LIB_DEBUG_${${INDI_PRIVATE_VAR_NS}_COMPONENT}) # debug not found => we are in release 230 | set(${INDI_PRIVATE_VAR_NS}_LIB_${${INDI_PRIVATE_VAR_NS}_COMPONENT} "${${INDI_PRIVATE_VAR_NS}_LIB_RELEASE_${${INDI_PRIVATE_VAR_NS}_COMPONENT}}") 231 | else() # both found 232 | set( 233 | ${INDI_PRIVATE_VAR_NS}_LIB_${${INDI_PRIVATE_VAR_NS}_COMPONENT} 234 | optimized ${${INDI_PRIVATE_VAR_NS}_LIB_RELEASE_${${INDI_PRIVATE_VAR_NS}_COMPONENT}} 235 | debug ${${INDI_PRIVATE_VAR_NS}_LIB_DEBUG_${${INDI_PRIVATE_VAR_NS}_COMPONENT}} 236 | ) 237 | endif() 238 | list(APPEND ${INDI_PUBLIC_VAR_NS}_LIBRARIES ${${INDI_PRIVATE_VAR_NS}_LIB_${${INDI_PRIVATE_VAR_NS}_COMPONENT}}) 239 | endif(NOT ${INDI_PRIVATE_VAR_NS}_LIB_RELEASE_${${INDI_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${INDI_PRIVATE_VAR_NS}_LIB_DEBUG_${${INDI_PRIVATE_VAR_NS}_COMPONENT}) 240 | endforeach(${INDI_PRIVATE_VAR_NS}_COMPONENT) 241 | 242 | # Check find_package arguments 243 | include(FindPackageHandleStandardArgs) 244 | if(${INDI_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${INDI_PUBLIC_VAR_NS}_FIND_QUIETLY) 245 | find_package_handle_standard_args( 246 | ${INDI_PUBLIC_VAR_NS} 247 | REQUIRED_VARS ${INDI_PUBLIC_VAR_NS}_LIBRARIES ${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR 248 | VERSION_VAR ${INDI_PUBLIC_VAR_NS}_VERSION 249 | ) 250 | else(${INDI_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${INDI_PUBLIC_VAR_NS}_FIND_QUIETLY) 251 | find_package_handle_standard_args(${INDI_PUBLIC_VAR_NS} "INDI not found" ${INDI_PUBLIC_VAR_NS}_LIBRARIES ${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR) 252 | endif(${INDI_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${INDI_PUBLIC_VAR_NS}_FIND_QUIETLY) 253 | else(${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR) 254 | set("${INDI_PUBLIC_VAR_NS}_FOUND" FALSE) 255 | if(${INDI_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${INDI_PUBLIC_VAR_NS}_FIND_QUIETLY) 256 | message(FATAL_ERROR "Could not find INDI include directory") 257 | endif(${INDI_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${INDI_PUBLIC_VAR_NS}_FIND_QUIETLY) 258 | endif(${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR) 259 | 260 | mark_as_advanced( 261 | ${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR 262 | ${INDI_PUBLIC_VAR_NS}_LIBRARIES 263 | ) 264 | 265 | # IN (args) 266 | indidebug("FIND_COMPONENTS") 267 | indidebug("FIND_REQUIRED") 268 | indidebug("FIND_QUIETLY") 269 | indidebug("FIND_VERSION") 270 | # OUT 271 | # Found 272 | indidebug("FOUND") 273 | indidebug("SERVER_FOUND") 274 | indidebug("DRIVERS_FOUND") 275 | indidebug("CLIENT_FOUND") 276 | indidebug("QT5CLIENT_FOUND") 277 | 278 | # Linking 279 | indidebug("INCLUDE_DIR") 280 | indidebug("DATA_DIR") 281 | indidebug("LIBRARIES") 282 | # Backward compatibility 283 | set(${INDI_PUBLIC_VAR_NS}_DRIVER_LIBRARIES ${${INDI_PUBLIC_VAR_NS}_LIBRARIES}) 284 | indidebug("DRIVER_LIBRARIES") 285 | # Version 286 | indidebug("MAJOR_VERSION") 287 | indidebug("MINOR_VERSION") 288 | indidebug("RELEASE_VERSION") 289 | indidebug("VERSION") 290 | --------------------------------------------------------------------------------