Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions indi_allsky/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,7 @@ class IndiAllSkyConfigBase(object):
"F_USER_VAR_SLOT" : "sensor_user_55",
"F_I2C_ADDRESS" : "0x52",
"F_TITLE_TEMPLATE" : "{name:s} - {label:s} - {probe:s}",
"FC37_ACTIVE_LOW" : True,
"OPENWEATHERMAP_APIKEY" : "",
"OPENWEATHERMAP_APIKEY_E": "",
"WUNDERGROUND_APIKEY" : "",
Expand Down Expand Up @@ -857,6 +858,9 @@ class IndiAllSkyConfigBase(object):
"CUSTOM_SLOT_9" : "sensor_user_18",
"CUSTOM_SLOT_9_MIN" : 0.0,
},
"RAIN_SENSOR" : {
"FC37_ACTIVE_LOW" : True,
},
"ADSB" : {
"ENABLE" : False,
"DUMP1090_URL" : 'https://localhost/dump1090/data/aircraft.json',
Expand Down
5 changes: 5 additions & 0 deletions indi_allsky/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,11 @@
SENSOR_USER_CAMERA_SQM_MAG = 8
SENSOR_USER_CAMERA_SQM_ADU = 9

RAIN_MAP_STR = {
0 : 'No Rain',
1 : 'Raining',
}


SENSOR_INDEX_MAP = {
'sensor_user_0' : 0,
Expand Down
2 changes: 2 additions & 0 deletions indi_allsky/devices/sensors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@

from .lightningSensorAs3935 import LightningSensorAs3935_SparkFun_SPI as blinka_sparkfun_lightning_sensor_as3935_spi
from .lightningSensorAs3935 import LightningSensorAs3935_SparkFun_I2C as blinka_sparkfun_lightning_sensor_as3935_i2c
from .rainSensorFc37 import RainSensorFc37 as blinka_rain_sensor_fc37

from .mqttBrokerSensor import MqttBrokerSensor as mqtt_broker_sensor

Expand Down Expand Up @@ -133,6 +134,7 @@
'kernel_temp_sensor_ds18x20_w1',
'blinka_sparkfun_lightning_sensor_as3935_spi',
'blinka_sparkfun_lightning_sensor_as3935_i2c',
'blinka_rain_sensor_fc37',
'mqtt_broker_sensor',
'temp_api_openweathermap',
'temp_api_weatherunderground',
Expand Down
70 changes: 70 additions & 0 deletions indi_allsky/devices/sensors/rainSensorFc37.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import logging

from .sensorBase import SensorBase
from ... import constants
from ..exceptions import SensorException

logger = logging.getLogger('indi_allsky')


class RainSensorFc37(SensorBase):

METADATA = {
'name': 'FC-37 Rain Sensor',
'description': 'FC-37 Rain Detection Sensor (digital output)',
'count': 1,
'labels': (
'Rain Detected',
),
'types': (
constants.SENSOR_PRECIPITATION,
),
}

def __init__(self, *args, **kwargs):
super(RainSensorFc37, self).__init__(*args, **kwargs)

pin_1_name = kwargs.get('pin_1_name')
if not pin_1_name:
raise SensorException('FC-37 sensor pin not configured (RAIN_SENSOR.__*_PIN_1 or TEMP_SENSOR.__*_PIN_1)')

try:
import board
import digitalio
except Exception as e:
raise SensorException('FC-37 sensor requires board/digitalio support: %s' % str(e)) from e

if not hasattr(board, pin_1_name):
raise SensorException('FC-37 sensor pin name "%s" is not valid' % pin_1_name)

self.sensor_pin = digitalio.DigitalInOut(getattr(board, pin_1_name))
self.sensor_pin.direction = digitalio.Direction.INPUT
self.sensor_pin.pull = digitalio.Pull.UP

self.active_low = bool(
self.config.get('RAIN_SENSOR', {}).get('FC37_ACTIVE_LOW', True)
)

logger.warning('[%s] Initialized FC-37 rain sensor on pin %s, active_low=%s', self.name, pin_1_name, self.active_low)

def update(self):
try:
raw_value = self.sensor_pin.value
except Exception as e:
raise SensorException('FC-37 sensor read failure: %s' % str(e)) from e

# FC-37 TFT digital output is typically low when water is detected.
detected = (not raw_value) if self.active_low else raw_value

rain_value = 1.0 if detected else 0.0
rain_state = constants.RAIN_MAP_STR.get(int(rain_value), 'Unknown')

logger.info('[%s] FC-37 rain sensor: %s (%s)', self.name, rain_state, rain_value)

return {'data': (rain_value,), 'state': rain_state}

def deinit(self):
try:
self.sensor_pin.deinit()
except Exception:
pass
8 changes: 7 additions & 1 deletion indi_allsky/flask/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,7 @@ def IMAGE_LABEL_TEMPLATE_validator(form, field):
'dew_heater_status' : '',
'fan_status' : '',
'wind_dir' : '',
'rain_sensor' : 'No Rain',
'custom_1' : '',
'custom_2' : '',
'custom_3' : '',
Expand Down Expand Up @@ -3990,6 +3991,9 @@ class IndiAllskyConfigForm(FlaskForm):
('blinka_sparkfun_lightning_sensor_as3935_spi', 'AS3935 SPI - (6 slots) [BETA]'),
('blinka_sparkfun_lightning_sensor_as3935_i2c', 'AS3935 i2c - (6 slots) [BETA]'),
),
'Rain Sensors' : (
('blinka_rain_sensor_fc37', 'FC-37 Rain Sensor - digital (1 slot)'),
),
'Remote' : (
('mqtt_broker_sensor', 'MQTT Broker Sensor - (10 slots)'),
),
Expand Down Expand Up @@ -4937,6 +4941,7 @@ class IndiAllskyConfigForm(FlaskForm):
TEMP_SENSOR__F_USER_VAR_SLOT = SelectField('Sensor F Initial Slot', choices=SENSOR_USER_VAR_SLOT_choices, validators=[SENSOR_USER_VAR_SLOT_validator])
TEMP_SENSOR__F_I2C_ADDRESS = StringField('I2C Address', validators=[DataRequired(), I2C_ADDRESS_validator])
TEMP_SENSOR__F_TITLE_TEMPLATE = StringField('Chart Title Template', validators=[DataRequired(), TEMP_SENSOR__TITLE_TEMPLATE_validator])
RAIN_SENSOR__FC37_ACTIVE_LOW = BooleanField('Rain Sensor FC-37 -Invert logic')
TEMP_SENSOR__OPENWEATHERMAP_APIKEY = PasswordField('OpenWeatherMap API Key', widget=PasswordInput(hide_value=False), validators=[TEMP_SENSOR__OPENWEATHERMAP_APIKEY_validator], render_kw={'autocomplete' : 'new-password'})
TEMP_SENSOR__WUNDERGROUND_APIKEY = PasswordField('Weather Underground API Key', widget=PasswordInput(hide_value=False), validators=[TEMP_SENSOR__WUNDERGROUND_APIKEY_validator], render_kw={'autocomplete' : 'new-password'})
TEMP_SENSOR__ASTROSPHERIC_APIKEY = PasswordField('Astrospheric API Key', widget=PasswordInput(hide_value=False), validators=[TEMP_SENSOR__ASTROSPHERIC_APIKEY_validator], render_kw={'autocomplete' : 'new-password'})
Expand Down Expand Up @@ -5279,6 +5284,7 @@ def validate(self):
result = False



if self.IMAGE_CROP_ROI_X1.data and self.IMAGE_CROP_ROI_Y1.data and self.IMAGE_CROP_ROI_X2.data and self.IMAGE_CROP_ROI_Y2.data:
if self.IMAGE_CROP_ROI_X2.data <= self.IMAGE_CROP_ROI_X1.data:
self.IMAGE_CROP_ROI_X2.errors.append('X2 must be greater than X1')
Expand Down Expand Up @@ -6053,7 +6059,6 @@ def validate(self):
self.TEMP_SENSOR__A_PIN_1.errors.append('Topics must be defined')
result = False


# sensor B
if self.TEMP_SENSOR__B_CLASSNAME.data:
if self.TEMP_SENSOR__B_CLASSNAME.data.startswith('blinka_'):
Expand Down Expand Up @@ -6606,6 +6611,7 @@ def validate(self):
})



for slot1, slot2 in itertools.combinations(check_sensor_slots, 2):
if not slot1['set'].isdisjoint(slot2['set']):
slot1['slot'].errors.append('Overlapping slots with {0:s}'.format(slot2['name']))
Expand Down
44 changes: 43 additions & 1 deletion indi_allsky/flask/templates/config.html
Original file line number Diff line number Diff line change
Expand Up @@ -2649,7 +2649,7 @@ <h2 class="accordion-header">
<div><a href="https://docs.python.org/3/library/string.html#formatspec" class="text-decoration-none link-info" target="_blank">Python format syntax</a></div>
<div><a href="https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes" class="text-decoration-none link-info" target="_blank">Python datetime format codes</a></div>
<div>Available variables:</div>
<div><pre>timestamp, ts, day_date, exposure, rational_exp, gain_f, temp, temp_unit,<br>sidereal_time, sqm, stars, detections, stack_method, stack_count, stretch<br>location, owner, latitude, longitude, kpindex, ovation_max,<br>sun_alt, moon_alt, moon_phase, sun_moon_sep, moon_up, sun_moon_sep,<br>mercury_alt, mercury_up, venus_alt, venus_up, venus_phase,<br>mars_alt, mars_up, jupiter_alt, jupiter_up, saturn_alt, saturn_up,<br>iss_alt, iss_up, iss_next_h, iss_next_alt, hst_alt, hst_up, hst_next_h,<br>hst_next_alt, tiangong_alt, tiangong_up, tiangong_next_h, tiangong_next_alt</pre></div>
<div><pre>timestamp, ts, day_date, exposure, rational_exp, gain_f, temp, temp_unit,<br>sidereal_time, sqm, stars, detections, stack_method, stack_count, stretch<br>location, owner, latitude, longitude, kpindex, ovation_max,<br>sun_alt, moon_alt, moon_phase, sun_moon_sep, moon_up, sun_moon_sep,<br>mercury_alt, mercury_up, venus_alt, venus_up, venus_phase,<br>mars_alt, mars_up, jupiter_alt, jupiter_up, saturn_alt, saturn_up,<br>iss_alt, iss_up, iss_next_h, iss_next_alt, hst_alt, hst_up, hst_next_h,<br>hst_next_alt, tiangong_alt, tiangong_up, tiangong_next_h, tiangong_next_alt,<br>rain_sensor</pre></div>
<div><a href="https://github.com/aaronwmorris/indi-allsky/wiki/Image-Labels" class="text-decoration-none link-info" target="_blank">Image Labels Wiki</a></div>
</div>
</div>
Expand Down Expand Up @@ -8092,6 +8092,24 @@ <h2 class="accordion-header">

<hr>

<div class="form-group row">
<div class="col-sm-2">
{{ form_config.RAIN_SENSOR__FC37_ACTIVE_LOW.label(class='col-form-label') }}
</div>
<div class="col-sm-2">
<div class="form-switch">
{{ form_config.RAIN_SENSOR__FC37_ACTIVE_LOW(id='RAIN_SENSOR__FC37_ACTIVE_LOW', class='form-check-input') }}
<div id="RAIN_SENSOR__FC37_ACTIVE_LOW-error" class="invalid-feedback text-danger" style="display: none;"></div>
</div>
</div>
<div class="col-sm-8">
<div>Invert the FC-37 sensor Digital Output logic. Signal default is 0 = No rain, 1 = Rain </div>
<div>*Note* In Overlay Template use rain_sensor:s which gives string display</div>
</div>
</div>

<hr>

<div class="form-group row">
<div class="col-sm-2">
{{ form_config.TEMP_SENSOR__DHT_USE_PULSEIO.label }}
Expand Down Expand Up @@ -10488,6 +10506,7 @@ <h2 class="accordion-header">
'VIRTUALSKY__SHOWPLANETS',
'VIRTUALSKY__SHOWPLANETLABELS',
'TEMP_SENSOR__DHT_USE_PULSEIO',
'RAIN_SENSOR__FC37_ACTIVE_LOW',
'TEMP_SENSOR__SHT3X_HEATER_NIGHT',
'TEMP_SENSOR__SHT3X_HEATER_DAY',
'TEMP_SENSOR__HTU31D_HEATER_NIGHT',
Expand Down Expand Up @@ -11429,6 +11448,29 @@ <h2 class="accordion-header">
group_on_ready('IMAGE_OVERLAY__ENABLE', group_fields_image_overlay, group_checkbox_fields_image_overlay);
group_on_ready('CIRCULAR_DISPLAY__ENABLE', group_fields_circular_display, group_checkbox_fields_circular_display);

// Enable/disable FC-37 Active Low toggle when any sensor slot has FC-37 selected
function updateFc37ActiveLowState() {
const sensorSlotIds = [
'TEMP_SENSOR__A_CLASSNAME',
'TEMP_SENSOR__B_CLASSNAME',
'TEMP_SENSOR__C_CLASSNAME',
'TEMP_SENSOR__D_CLASSNAME',
'TEMP_SENSOR__E_CLASSNAME',
'TEMP_SENSOR__F_CLASSNAME',
];
const fc37Selected = sensorSlotIds.some(function(id) {
return $('#' + id).val() === 'blinka_rain_sensor_fc37';
});
const $toggle = $('#RAIN_SENSOR__FC37_ACTIVE_LOW');
$toggle.prop('disabled', !fc37Selected);
$toggle.closest('.form-group.row').toggleClass('text-muted', !fc37Selected).css('opacity', fc37Selected ? '' : '0.5');
}

$('#TEMP_SENSOR__A_CLASSNAME, #TEMP_SENSOR__B_CLASSNAME, #TEMP_SENSOR__C_CLASSNAME, #TEMP_SENSOR__D_CLASSNAME, #TEMP_SENSOR__E_CLASSNAME, #TEMP_SENSOR__F_CLASSNAME').on('change', updateFc37ActiveLowState);

updateFc37ActiveLowState();

});

// Open the camera settings accordion section that matches the selected
// CAMERA_INTERFACE value, both on page load and when the selection changes.
Expand Down
3 changes: 3 additions & 0 deletions indi_allsky/flask/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2820,6 +2820,7 @@ def get_context(self):
'TEMP_SENSOR__F_I2C_ADDRESS' : self.indi_allsky_config.get('TEMP_SENSOR', {}).get('F_I2C_ADDRESS', '0x52'),
'TEMP_SENSOR__F_USER_VAR_SLOT' : self.indi_allsky_config.get('TEMP_SENSOR', {}).get('F_USER_VAR_SLOT', 'sensor_user_55'),
'TEMP_SENSOR__F_TITLE_TEMPLATE' : self.indi_allsky_config.get('TEMP_SENSOR', {}).get('F_TITLE_TEMPLATE', '{name:s} - {label:s} - {probe:s}'),
'RAIN_SENSOR__FC37_ACTIVE_LOW' : self.indi_allsky_config.get('RAIN_SENSOR', {}).get('FC37_ACTIVE_LOW', True),
'TEMP_SENSOR__OPENWEATHERMAP_APIKEY' : self.indi_allsky_config.get('TEMP_SENSOR', {}).get('OPENWEATHERMAP_APIKEY', ''),
'TEMP_SENSOR__WUNDERGROUND_APIKEY' : self.indi_allsky_config.get('TEMP_SENSOR', {}).get('WUNDERGROUND_APIKEY', ''),
'TEMP_SENSOR__ASTROSPHERIC_APIKEY' : self.indi_allsky_config.get('TEMP_SENSOR', {}).get('ASTROSPHERIC_APIKEY', ''),
Expand Down Expand Up @@ -3216,6 +3217,7 @@ def dispatch_request(self):
'MANUAL_GPIO',
'DEVICE',
'TEMP_SENSOR',
'RAIN_SENSOR',
'THUMBNAILS',
'HEALTHCHECK',
'CHARTS',
Expand Down Expand Up @@ -3852,6 +3854,7 @@ def dispatch_request(self):
self.indi_allsky_config['TEMP_SENSOR']['F_USER_VAR_SLOT'] = str(request.json['TEMP_SENSOR__F_USER_VAR_SLOT'])
self.indi_allsky_config['TEMP_SENSOR']['F_I2C_ADDRESS'] = str(request.json['TEMP_SENSOR__F_I2C_ADDRESS'])
self.indi_allsky_config['TEMP_SENSOR']['F_TITLE_TEMPLATE'] = str(request.json['TEMP_SENSOR__F_TITLE_TEMPLATE'])
self.indi_allsky_config['RAIN_SENSOR']['FC37_ACTIVE_LOW'] = bool(request.json.get('RAIN_SENSOR__FC37_ACTIVE_LOW', True))
self.indi_allsky_config['TEMP_SENSOR']['OPENWEATHERMAP_APIKEY'] = str(request.json['TEMP_SENSOR__OPENWEATHERMAP_APIKEY'])
self.indi_allsky_config['TEMP_SENSOR']['WUNDERGROUND_APIKEY'] = str(request.json['TEMP_SENSOR__WUNDERGROUND_APIKEY'])
self.indi_allsky_config['TEMP_SENSOR']['ASTROSPHERIC_APIKEY'] = str(request.json['TEMP_SENSOR__ASTROSPHERIC_APIKEY'])
Expand Down
19 changes: 15 additions & 4 deletions indi_allsky/processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2787,8 +2787,7 @@ def populateSatelliteData(self):

def get_image_label(self, i_ref, adsb_aircraft_list, custom_hook_data):
# gain is int, gain_f is float
image_label_tmpl = self.config.get('IMAGE_LABEL_TEMPLATE', '{timestamp:%Y%m%d %H:%M:%S}\nExposure {exposure:0.6f}\nGain {gain_f:0.2f}\nTemp {temp:0.1f}{temp_unit:s}\nStars {stars:d}')

image_label_tmpl = self.config.get('IMAGE_LABEL_TEMPLATE', '{timestamp:%Y%m%d %H:%M:%S}\nExposure {exposure:0.6f}\nGain {gain_f:0.2f}\nTemp {temp:0.1f}{temp_unit:s}\nRain {rain_sensor}\nStars {stars:d}')

if self.config.get('TEMP_DISPLAY') == 'f':
temp_unit = 'F'
Expand Down Expand Up @@ -2951,11 +2950,23 @@ def get_image_label(self, i_ref, adsb_aircraft_list, custom_hook_data):
# 0 == ccd_temp
label_data['temp'] = label_data['sensor_temp_0']


for x, sensor_data in enumerate(self.sensors_user_av):
label_data['sensor_user_{0:d}'.format(x)] = sensor_data


# rain sensor state - scan TEMP_SENSOR A-F slots for FC-37 classname
rain_sensor_label = 'No Rain'
for _slot_letter in ('A', 'B', 'C', 'D', 'E', 'F'):
if self.config.get('TEMP_SENSOR', {}).get('{0:s}_CLASSNAME'.format(_slot_letter)) == 'blinka_rain_sensor_fc37':
_rain_slot_key = self.config.get('TEMP_SENSOR', {}).get('{0:s}_USER_VAR_SLOT'.format(_slot_letter), 'sensor_user_10')
_rain_slot_idx = constants.SENSOR_INDEX_MAP.get(_rain_slot_key)
if _rain_slot_idx is not None:
_rain_state = int(round(self.sensors_user_av[_rain_slot_idx]))
rain_sensor_label = constants.RAIN_MAP_STR.get(_rain_state, 'No Rain')
break

label_data['rain_sensor'] = rain_sensor_label

# dew heater
if self.sensors_user_av[constants.SENSOR_USER_DEW_HEATER_LEVEL]:
label_data['dew_heater_status'] = 'On'
Expand Down Expand Up @@ -3000,7 +3011,7 @@ def get_image_label(self, i_ref, adsb_aircraft_list, custom_hook_data):
#label_data['custom_9'] = ''


image_label = image_label_tmpl.format(**label_data) # fill in the data
image_label = image_label_tmpl.format(**label_data)


# Add moon mode indicator
Expand Down