Skip to content
Merged
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
66 changes: 45 additions & 21 deletions TankAlarm-092025-Client-Hologram/INSTALLATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,28 +74,48 @@ File: TankAlarm092025-Test.ino

## Software Configuration

### Step 1: Configure the Code
### Step 1: Configure SD Card (REQUIRED)
1. **Create SD Card Configuration**:
- Copy `tank_config_example.txt` to SD card as `tank_config.txt`
- Edit `tank_config.txt` with your specific settings

2. **Critical Settings (REQUIRED)**:
```
# Update these values for your setup - ALL SETTINGS REQUIRED
SITE_NAME=Your Tank Farm Name
TANK_NUMBER=1
HOLOGRAM_DEVICE_KEY=your_actual_device_key_here
ALARM_PHONE_PRIMARY=+15551234567
ALARM_PHONE_SECONDARY=+15559876543
DAILY_REPORT_PHONE=+15555551234
```

3. **Tank Physical Configuration**:
```
TANK_HEIGHT_INCHES=120
HIGH_ALARM_INCHES=100
LOW_ALARM_INCHES=12
```

4. **Insert SD Card**: Place configured SD card in device before powering on

**IMPORTANT**: The device will not start without a properly configured `tank_config.txt` file on the SD card. The device will halt with error messages if:
- SD card is not inserted
- `tank_config.txt` file is missing
- HOLOGRAM_DEVICE_KEY is not set
- ALARM_PHONE_PRIMARY is not set

### Step 2: Hardware Configuration (config.h)
1. **Copy Configuration Template**:
- Copy `config_template.h` to `config.h`
- Edit `config.h` with your specific settings
- Copy `config_template.h` to `config.h` (only if missing)
- This file now only contains hardware-specific constants

2. **Select Tank Level Sensor Type**:
```cpp
// Choose sensor type: DIGITAL_FLOAT, ANALOG_VOLTAGE, or CURRENT_LOOP
#define SENSOR_TYPE DIGITAL_FLOAT
```

3. **Update Configuration Values**:
```cpp
// Replace with your actual Hologram.io device key
#define HOLOGRAM_DEVICE_KEY "your_device_key_here"

// Update with your phone numbers (include country code)
#define ALARM_PHONE_PRIMARY "+12223334444"
#define ALARM_PHONE_SECONDARY "+15556667777"
#define DAILY_REPORT_PHONE "+18889990000"
```

4. **Configure Sensor-Specific Settings**:

**For Digital Float Switch (SENSOR_TYPE = DIGITAL_FLOAT)**:
Expand Down Expand Up @@ -146,16 +166,16 @@ File: TankAlarm092025-Test.ino
#define DAILY_REPORT_HOURS 24
```

### Step 2: Update Main Code
1. In `TankAlarm092025-Hologram.ino`, change this line:
### Step 3: Update Main Code
1. In `TankAlarm-092025-Client-Hologram.ino`, change this line:
```cpp
// Change from:
#include "config_template.h"
// To:
#include "config.h"
```

### Step 3: Upload Code
### Step 4: Upload Code
1. Connect MKR NB 1500 to computer via USB
2. Select correct board: Tools → Board → Arduino MKR NB 1500
3. Select correct port: Tools → Port → (your port)
Expand Down Expand Up @@ -260,10 +280,14 @@ File: TankAlarm092025-Test.ino
- **Annually**: Clean enclosure, inspect connections

### Updating Configuration
1. Connect to computer via USB
2. Modify config.h as needed
3. Re-upload sketch
4. Test new configuration
**NEW APPROACH - Field Configurable:**
1. Power off device
2. Remove SD card from device
3. Edit `tank_config.txt` on computer
4. Insert SD card back into device
5. Power on device - new configuration will be loaded and validated

**CRITICAL**: Device will not start without valid SD card configuration.

### Data Retrieval
1. Remove SD card from system
Expand Down
124 changes: 71 additions & 53 deletions TankAlarm-092025-Client-Hologram/TankAlarm-092025-Client-Hologram.ino
Original file line number Diff line number Diff line change
Expand Up @@ -195,44 +195,44 @@ bool powerFailureRecovery = false;
#endif
String logFileName = LOG_FILE_NAME;

// SD Card configuration variables (loaded from SD card config file)
String siteLocationName = SITE_LOCATION_NAME;
int tankNumber = TANK_NUMBER;
float inchesPerUnit = INCHES_PER_UNIT;
float tankHeightInches = TANK_HEIGHT_INCHES;
float highAlarmInches = HIGH_ALARM_INCHES;
float lowAlarmInches = LOW_ALARM_INCHES;
bool digitalHighAlarm = DIGITAL_HIGH_ALARM;
bool digitalLowAlarm = DIGITAL_LOW_ALARM;
float largeDecreaseThreshold = LARGE_DECREASE_THRESHOLD_INCHES;
int largeDecreaseWaitHours = LARGE_DECREASE_WAIT_HOURS;

// Network and communication configuration (loaded from SD card)
String hologramDeviceKey = HOLOGRAM_DEVICE_KEY;
String serverDeviceKey = SERVER_DEVICE_KEY; // Server's device ID for remote commands
String alarmPhonePrimary = ALARM_PHONE_PRIMARY;
String alarmPhoneSecondary = ALARM_PHONE_SECONDARY;
String dailyReportPhone = DAILY_REPORT_PHONE;
String hologramAPN = HOLOGRAM_APN;

// Timing configuration (loaded from SD card)
int sleepIntervalHours = SLEEP_INTERVAL_HOURS;
int dailyReportHours = DAILY_REPORT_HOURS;
String dailyReportTime = DAILY_REPORT_TIME;
// SD Card configuration variables (loaded from SD card config file - REQUIRED)
String siteLocationName = "Unknown Site";
int tankNumber = 1;
float inchesPerUnit = 1.0;
float tankHeightInches = 120.0;
float highAlarmInches = 100.0;
float lowAlarmInches = 12.0;
bool digitalHighAlarm = true;
bool digitalLowAlarm = false;
float largeDecreaseThreshold = 24.0;
int largeDecreaseWaitHours = 2;

// Network and communication configuration (loaded from SD card - REQUIRED)
String hologramDeviceKey = "";
String serverDeviceKey = ""; // Server's device ID for remote commands
String alarmPhonePrimary = "";
String alarmPhoneSecondary = "";
String dailyReportPhone = "";
String hologramAPN = "hologram";

// Timing configuration (loaded from SD card - REQUIRED)
int sleepIntervalHours = 1;
int dailyReportHours = 24;
String dailyReportTime = "05:00";

// Time synchronization variables
bool timeIsSynced = false;
unsigned long lastTimeSyncMillis = 0;
const unsigned long TIME_SYNC_INTERVAL_MS = 24 * 60 * 60 * 1000; // Sync once per day

// Power management variables
// Power management variables (loaded from SD card - REQUIRED)
volatile bool wakeFromCellular = false; // Flag set when woken by cellular data
volatile int wakeReason = WAKE_REASON_TIMER; // Reason for last wake
unsigned long lastCellularCheck = 0; // Last time we checked for cellular data
bool deepSleepMode = DEEP_SLEEP_MODE; // Whether to use deep sleep mode
int shortSleepMinutes = SHORT_SLEEP_MINUTES; // Short sleep duration for frequent checks
int normalSleepHours = NORMAL_SLEEP_HOURS; // Normal sleep duration between readings
bool wakeOnPingEnabled = ENABLE_WAKE_ON_PING; // Wake on ping functionality
bool deepSleepMode = false; // Whether to use deep sleep mode
int shortSleepMinutes = 10; // Short sleep duration for frequent checks
int normalSleepHours = 1; // Normal sleep duration between readings
bool wakeOnPingEnabled = true; // Wake on ping functionality

// Height calibration system
#define MAX_CALIBRATION_POINTS 10
Expand Down Expand Up @@ -270,16 +270,16 @@ void processSMSCommand(String command, String phoneNumber);
void sendCalibrationSMS(String phoneNumber);
float getCurrentSensorReading();

// Network configuration (loaded from SD card)
int connectionTimeoutMs = CONNECTION_TIMEOUT_MS;
int smsRetryAttempts = SMS_RETRY_ATTEMPTS;
// Network configuration (loaded from SD card - REQUIRED)
int connectionTimeoutMs = 30000;
int smsRetryAttempts = 3;

// Log file names (loaded from SD card)
String hourlyLogFile = SD_HOURLY_LOG_FILE;
String dailyLogFile = SD_DAILY_LOG_FILE;
String alarmLogFile = SD_ALARM_LOG_FILE;
String decreaseLogFile = SD_DECREASE_LOG_FILE;
String reportLogFile = SD_REPORT_LOG_FILE;
String hourlyLogFile = "hourly_log.txt";
String dailyLogFile = "daily_log.txt";
String alarmLogFile = "alarm_log.txt";
String decreaseLogFile = "decrease_log.txt";
String reportLogFile = "report_log.txt";

void setup() {
// Initialize serial communication for debugging
Expand Down Expand Up @@ -1008,22 +1008,27 @@ String getCurrentTimestamp() {
// Load configuration from SD card
void loadSDCardConfiguration() {
if (!SD.begin(SD_CARD_CS_PIN)) {
logEvent("Failed to initialize SD card for configuration loading");
return;
Serial.println("CRITICAL ERROR: Failed to initialize SD card for client configuration loading");
Serial.println("SD card configuration is REQUIRED for operation");
while (true) {
// Halt execution - SD card config is required
delay(5000);
Serial.println("Please insert SD card with tank_config.txt and restart");
}
}

File configFile = SD.open(SD_CONFIG_FILE);
if (!configFile) {
#ifdef ENABLE_SERIAL_DEBUG
if (ENABLE_SERIAL_DEBUG) Serial.println("Config file not found, using defaults");
#endif
logEvent("Config file not found, using defaults from config.h");
return;
Serial.println("CRITICAL ERROR: Client config file not found on SD card");
Serial.println("tank_config.txt is REQUIRED for operation");
while (true) {
// Halt execution - SD card config is required
delay(5000);
Serial.println("Please create tank_config.txt on SD card and restart");
}
}

#ifdef ENABLE_SERIAL_DEBUG
if (ENABLE_SERIAL_DEBUG) Serial.println("Loading configuration from SD card...");
#endif
Serial.println("Loading client configuration from SD card...");

while (configFile.available()) {
String line = configFile.readStringUntil('\n');
Expand Down Expand Up @@ -1109,15 +1114,28 @@ void loadSDCardConfiguration() {

configFile.close();

String configMsg = "Configuration loaded - Site: " + siteLocationName +
// Validate critical configuration
if (hologramDeviceKey.length() == 0 || hologramDeviceKey == "your_device_key_here") {
Serial.println("CRITICAL ERROR: HOLOGRAM_DEVICE_KEY not configured in tank_config.txt");
while (true) {
delay(5000);
Serial.println("Please set HOLOGRAM_DEVICE_KEY in tank_config.txt and restart");
}
}

if (alarmPhonePrimary.length() == 0 || alarmPhonePrimary == "+12223334444") {
Copy link

Copilot AI Sep 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hardcoded placeholder value +12223334444 should be defined as a constant rather than a magic string. If this placeholder changes in the config template, this validation could miss it. Consider defining #define DEFAULT_PHONE_PLACEHOLDER \"+12223334444\" or validate against the actual template file content.

Copilot uses AI. Check for mistakes.
Serial.println("CRITICAL ERROR: ALARM_PHONE_PRIMARY not configured in tank_config.txt");
while (true) {
delay(5000);
Serial.println("Please set ALARM_PHONE_PRIMARY in tank_config.txt and restart");
}
}

String configMsg = "Client configuration loaded successfully - Site: " + siteLocationName +
", Tank: " + String(tankNumber) +
", Height: " + String(tankHeightInches) + "in" +
", Daily Report: " + dailyReportTime;
logEvent(configMsg);

#ifdef ENABLE_SERIAL_DEBUG
if (ENABLE_SERIAL_DEBUG) Serial.println(configMsg);
#endif
Serial.println(configMsg);
}

// Convert sensor reading to inches
Expand Down
81 changes: 13 additions & 68 deletions TankAlarm-092025-Client-Hologram/config_template.h
Original file line number Diff line number Diff line change
@@ -1,32 +1,18 @@
//
// Configuration file for Tank Alarm 092025
// Copy this file and rename to config.h, then update with your specific values
// This file now contains only essential compile-time constants
// Most configuration is now loaded from tank_config.txt on SD card
//

#ifndef CONFIG_H
#define CONFIG_H

// Hologram.io Configuration
#define HOLOGRAM_DEVICE_KEY "your_device_key_here" // Replace with your actual device key
#define SERVER_DEVICE_KEY "server_device_key_here" // Server's Hologram device ID for remote commands
#define HOLOGRAM_APN "hologram" // Hologram.io APN (usually stays "hologram")

// Phone Numbers for Notifications (include country code, e.g., +1 for US)
#define ALARM_PHONE_PRIMARY "+12223334444" // Primary emergency contact
#define ALARM_PHONE_SECONDARY "+15556667777" // Secondary emergency contact
#define DAILY_REPORT_PHONE "+18889990000" // Daily report recipient

// Timing Configuration (in hours)
#define SLEEP_INTERVAL_HOURS 1 // How often to check tank level (default: 1 hour)
#define DAILY_REPORT_HOURS 24 // How often to send daily report (default: 24 hours)
#define DAILY_REPORT_TIME "05:00" // Time of day for daily report in HH:MM format (24-hour)

// Pin Configuration (adjust if using different pins)
// Pin Configuration (hardware specific - cannot be changed at runtime)
#define TANK_LEVEL_PIN 7 // Tank level sensor input pin
#define RELAY_CONTROL_PIN 5 // Relay output control pin
#define SD_CARD_CS_PIN 4 // SD card chip select pin (works for both MKR SD PROTO and MKR ETH shields)

// Tank Level Sensor Configuration
// Sensor Type Configuration (hardware specific)
// Sensor Types: DIGITAL_FLOAT, ANALOG_VOLTAGE, CURRENT_LOOP
#define SENSOR_TYPE DIGITAL_FLOAT // Type of tank level sensor

Expand All @@ -35,75 +21,34 @@
#define SENSOR_DEBOUNCE_MS 100 // Debounce delay for sensor reading

// Analog Voltage Sensor Configuration (SENSOR_TYPE = ANALOG_VOLTAGE)
// For Dwyer 626 series ratiometric 0.5-4.5V pressure sensors
// Can use A1-A4 pins on MKR RELAY shield with convenient screw terminals
#define ANALOG_SENSOR_PIN A1 // Analog input pin for voltage sensor (A1, A2, A3, or A4)
#define VOLTAGE_MIN 0.5 // Minimum sensor voltage (V)
#define VOLTAGE_MAX 4.5 // Maximum sensor voltage (V)
#define TANK_EMPTY_VOLTAGE 0.5 // Voltage when tank is empty (V)
#define TANK_FULL_VOLTAGE 4.5 // Voltage when tank is full (V)
// Alarm thresholds are now configured in inches using HIGH_ALARM_INCHES and LOW_ALARM_INCHES
// See tank configuration section above for inches-based alarm settings

// Multiple Analog Sensor Support (Optional - for multiple tank monitoring)
// Uncomment and configure additional sensors if needed
// #define ENABLE_MULTI_ANALOG_SENSORS true
// #define ANALOG_SENSOR_PIN_2 A2 // Second analog sensor
// #define ANALOG_SENSOR_PIN_3 A3 // Third analog sensor
// #define ANALOG_SENSOR_PIN_4 A4 // Fourth analog sensor

// Current Loop Sensor Configuration (SENSOR_TYPE = CURRENT_LOOP)
// For 4-20mA sensors using NCD.io 4-channel current loop I2C module
#define I2C_CURRENT_LOOP_ADDRESS 0x48 // I2C address of NCD.io module
#define CURRENT_LOOP_CHANNEL 0 // Channel number (0-3) on NCD.io module
#define CURRENT_MIN 4.0 // Minimum current (mA)
#define CURRENT_MAX 20.0 // Maximum current (mA)
#define TANK_EMPTY_CURRENT 4.0 // Current when tank is empty (mA)
#define TANK_FULL_CURRENT 20.0 // Current when tank is full (mA)
// Alarm thresholds are now configured in inches using HIGH_ALARM_INCHES and LOW_ALARM_INCHES
// See tank configuration section above for inches-based alarm settings

// Logging Configuration
#define LOG_FILE_NAME "tanklog.txt" // SD card log file name
#define ENABLE_SERIAL_DEBUG true // Enable/disable serial output for debugging

// Network Configuration
#define CONNECTION_TIMEOUT_MS 30000 // Network connection timeout (30 seconds)
#define SMS_RETRY_ATTEMPTS 3 // Number of retry attempts for SMS sending
// System Buffer Sizes and Hardware Limits (memory allocation at compile time)
#define MAX_CALIBRATION_POINTS 10
#define CALIBRATION_FILE_NAME "calibration.txt"

// Power Management
#define ENABLE_LOW_POWER_MODE true // Enable low power sleep modes
// Network Configuration (timeouts and hardware limits)
#define WAKE_CHECK_DURATION_MS 5000 // How long to stay awake for each check
#define SHORT_SLEEP_MINUTES 10 // Short sleep duration for active monitoring (minutes)
#define NORMAL_SLEEP_HOURS 1 // Normal sleep duration between readings (hours)
#define ENABLE_WAKE_ON_PING true // Enable wake-on-ping functionality
#define DEEP_SLEEP_MODE false // Use deep sleep mode for maximum power savings

// Tank Configuration for Inches/Feet Measurements
#define TANK_NUMBER 1 // Tank number identifier (1-99)
#define SITE_LOCATION_NAME "Your Site Name" // Site location name for reports
#define INCHES_PER_UNIT 1.0 // Inches per sensor unit (calibration factor)
#define TANK_HEIGHT_INCHES 120 // Total tank height in inches

// Alarm Thresholds in Inches/Feet (for analog/current loop sensors)
#define HIGH_ALARM_INCHES 100 // High alarm threshold in inches
#define LOW_ALARM_INCHES 12 // Low alarm threshold in inches

// Digital Float Switch Alarm Configuration (for DIGITAL_FLOAT sensors)
#define DIGITAL_HIGH_ALARM true // Enable high alarm for digital float
#define DIGITAL_LOW_ALARM false // Enable low alarm for digital float

// Large Decrease Detection
#define ENABLE_LARGE_DECREASE_DETECTION true // Enable detection of large decreases
#define LARGE_DECREASE_THRESHOLD_INCHES 24 // Threshold for large decrease in inches
#define LARGE_DECREASE_WAIT_HOURS 2 // Hours to wait before logging large decrease
// Logging Configuration (system limits)
#define ENABLE_SERIAL_DEBUG true // Enable/disable serial output for debugging
#define LOG_FILE_NAME "tanklog.txt" // SD card log file name

// SD Card Configuration Files
#define SD_CONFIG_FILE "tank_config.txt" // SD card configuration file
#define SD_HOURLY_LOG_FILE "hourly_log.txt" // Hourly data log file
#define SD_DAILY_LOG_FILE "daily_log.txt" // Daily report log file
#define SD_ALARM_LOG_FILE "alarm_log.txt" // Alarm event log file
#define SD_DECREASE_LOG_FILE "decrease_log.txt" // Large decrease log file
#define SD_REPORT_LOG_FILE "report_log.txt" // Daily report transmission log file

// No fallback defaults - SD card configuration is required

#endif // CONFIG_H
Loading