Simple read of moisture levels via cron job to text file

I want something basic that I can run from a cron job to dump all the flower powers soil moisture levels out to a text file. The dump out to text file will be as simple as > text.txt on the end of the cron job. Most of the code is “borrowed” from other examples around the web. This is what I’ve got but I can’t get the loop right. I’m a very amateur coder :frowning:

This is what I get from the following code (the * are removed text):

pi@raspberrypi ~ $ sudo node fp.js
connectAndSetup
connectAndSetup
friendly name = Flower power *
system id = 90:03:*
soil moisture = 19.88%
disconnected!

My “awesome” code:

var async = require(‘async’);

var events = require(‘events’);
var util = require(‘util’);

var NobleDevice = require(‘noble-device’);

var LIVE_SERVICE_UUID = ‘39e1fa0084a811e2afba0002a5d5c51b’;
var CALIBRATION_SERVICE_UUID = ‘39e1fe0084a811e2afba0002a5d5c51b’;

var SUNLIGHT_UUID = ‘39e1fa0184a811e2afba0002a5d5c51b’;
var SOIL_EC_UUID = ‘39e1fa0284a811e2afba0002a5d5c51b’;
var SOIL_TEMPERATURE_UUID = ‘39e1fa0384a811e2afba0002a5d5c51b’;
var AIR_TEMPERATURE_UUID = ‘39e1fa0484a811e2afba0002a5d5c51b’;
var SOIL_MOISTURE_UUID = ‘39e1fa0584a811e2afba0002a5d5c51b’;
var LIVE_MODE_PERIOD_UUID = ‘39e1fa0684a811e2afba0002a5d5c51b’;
var LED_UUID = ‘39e1fa0784a811e2afba0002a5d5c51b’;
var LAST_MOVE_DATE_UUID = ‘39e1fa0884a811e2afba0002a5d5c51b’;
var CALIBRATED_SOIL_MOISTURE_UUID = ‘39e1fa0984a811e2afba0002a5d5c51b’;
var CALIBRATED_AIR_TEMPERATURE_UUID = ‘39e1fa0a84a811e2afba0002a5d5c51b’;
var CALIBRATED_DLI_UUID = ‘39e1fa0b84a811e2afba0002a5d5c51b’;
var CALIBRATED_EA_UUID = ‘39e1fa0c84a811e2afba0002a5d5c51b’;
var CALIBRATED_ECB_UUID = ‘39e1fa0d84a811e2afba0002a5d5c51b’;
var CALIBRATED_EC_POROUS_UUID = ‘39e1fa0e84a811e2afba0002a5d5c51b’;

var FRIENDLY_NAME_UUID = ‘39e1fe0384a811e2afba0002a5d5c51b’;
var COLOR_UUID = ‘39e1fe0484a811e2afba0002a5d5c51b’;

function FlowerPower(peripheral) {
NobleDevice.call(this, peripheral);

this.uuid = peripheral.uuid;
this.name = peripheral.advertisement.localName;
}

NobleDevice.Util.inherits(FlowerPower, NobleDevice);
NobleDevice.Util.mixin(FlowerPower, NobleDevice.BatteryService);
NobleDevice.Util.mixin(FlowerPower, NobleDevice.DeviceInformationService, [
‘readSystemId’,
‘readSerialNumber’,
‘readFirmwareRevision’,
‘readHardwareRevision’,
‘readManufacturerName’
]);

FlowerPower.SCAN_UUIDS = [LIVE_SERVICE_UUID];

FlowerPower.prototype.toString = function() {
return JSON.stringify({
uuid: this.uuid,
name: this.name
});
};

FlowerPower.prototype.readFriendlyName = function(callback) {
this.readStringCharacteristic(CALIBRATION_SERVICE_UUID, FRIENDLY_NAME_UUID, callback);
};

FlowerPower.prototype.convertSoilMoistureData = function(data) {
var rawValue = data.readUInt16LE(0) * 1.0;

var soilMoisture = 11.4293 + (0.0000000010698 * Math.pow(rawValue, 4.0) - 0.00000152538 * Math.pow(rawValue, 3.0) + 0.000866976 * Math.pow(rawValue, 2.0) - 0.169422 * rawValue);

soilMoisture = 100.0 * (0.0000045 * Math.pow(soilMoisture, 3.0) - 0.00055 * Math.pow(soilMoisture, 2.0) + 0.0292 * soilMoisture - 0.053);

if (soilMoisture < 0.0) {
soilMoisture = 0.0;
} else if (soilMoisture > 60.0) {
soilMoisture = 60.0;
}

return soilMoisture;
};

FlowerPower.prototype.readSoilMoisture = function(callback) {
this.readDataCharacteristic(LIVE_SERVICE_UUID, SOIL_MOISTURE_UUID, function(error, data) {
if (error) {
return callback(error);
}

var soilMoisture = this.convertSoilMoistureData(data);
callback(null, soilMoisture);

}.bind(this));
};

FlowerPower.prototype.onSoilMoistureChange = function(data) {
var soilMoisture = this.convertSoilMoistureData(data);

this.emit(‘soilMoistureChange’, soilMoisture);
};

FlowerPower.prototype.notifySoilMoisture = function(callback) {
this.notifyCharacteristic(LIVE_SERVICE_UUID, SOIL_MOISTURE_UUID, true, this.onSoilMoistureChange.bind(this), callback);
};

FlowerPower.prototype.unnotifySoilMoisture = function(callback) {
this.notifyCharacteristic(LIVE_SERVICE_UUID, SOIL_MOISTURE_UUID, false, this.onSoilMoistureChange.bind(this), callback);
};

FlowerPower.prototype.readCalibratedSoilMoisture = function(callback) {
this.readFloatLECharacteristic(LIVE_SERVICE_UUID, CALIBRATED_SOIL_MOISTURE_UUID, callback);
};

FlowerPower.prototype.onCalibratedSoilMoistureChange = function(value) {
this.emit(‘calibratedSoilMoistureChange’, value.readFloatLE(0));
};

FlowerPower.prototype.notifyCalibratedSoilMoisture = function(callback) {
this.notifyCharacteristic(LIVE_SERVICE_UUID, CALIBRATED_SOIL_MOISTURE_UUID, true, this.onCalibratedSoilMoistureChange.bind(this), callback);
};

FlowerPower.prototype.unnotifyCalibratedSoilMoisture = function(callback) {
this.notifyCharacteristic(LIVE_SERVICE_UUID, CALIBRATED_SOIL_MOISTURE_UUID, false, this.onCalibratedSoilMoistureChange.bind(this), callback);
};

FlowerPower.prototype.enableLiveModeWithPeriod = function(period, callback) {
this.notifySunlight(function() {
this.notifySoilElectricalConductivity(function() {
this.notifySoilTemperature(function() {
this.notifyAirTemperature(function() {
this.notifySoilMoisture(function() {
this.writeDataCharacteristic(LIVE_SERVICE_UUID, LIVE_MODE_PERIOD_UUID, new Buffer([period]), callback);
}.bind(this));
}.bind(this));
}.bind(this));
}.bind(this));
}.bind(this));
};

FlowerPower.prototype.enableLiveMode = function(callback) {
this.enableLiveModeWithPeriod(1, callback);
};

FlowerPower.prototype.disableLiveMode = function(callback) {
this.writeDataCharacteristic(LIVE_SERVICE_UUID, LIVE_MODE_PERIOD_UUID, new Buffer([0x00]), function() {
this.unnotifySunlight(function() {
this.unnotifySoilElectricalConductivity(function() {
this.unnotifySoilTemperature(function() {
this.unnotifyAirTemperature(function() {
this.unnotifySoilMoisture(function() {
callback();
}.bind(this));
}.bind(this));
}.bind(this));
}.bind(this));
}.bind(this));
}.bind(this));
};

FlowerPower.prototype.enableCalibratedLiveModeWithPeriod = function(period, callback) {
this.notifyCalibratedSoilMoisture(function() {
this.notifyCalibratedAirTemperatureChange(function() {
this.notifyCalibratedSunlight(function() {
this.notifyCalibratedEa(function() {
this.notifyCalibratedEcb(function() {
this.notifyCalibratedEcPorous(function() {
this.writeDataCharacteristic(LIVE_SERVICE_UUID, LIVE_MODE_PERIOD_UUID, new Buffer([period]), callback);
}.bind(this));
}.bind(this));
}.bind(this));
}.bind(this));
}.bind(this));
}.bind(this));
};

FlowerPower.prototype.enableCalibratedLiveMode = function(callback) {
this.enableCalibratedLiveModeWithPeriod(1, callback);
};

FlowerPower.prototype.disableCalibratedLiveMode = function(callback) {
this.writeDataCharacteristic(LIVE_SERVICE_UUID, LIVE_MODE_PERIOD_UUID, new Buffer([0x00]), function() {
this.unnotifyCalibratedSoilMoisture(function() {
this.unnotifyCalibratedAirTemperatureChange(function() {
this.unnotifyCalibratedSunlight(function() {
this.unnotifyCalibratedEa(function() {
this.unnotifyCalibratedEcb(function() {
this.unnotifyCalibratedEcPorous(function() {
callback();
}.bind(this));
}.bind(this));
}.bind(this));
}.bind(this));
}.bind(this));
}.bind(this));
}.bind(this));
};

var hasCalibratedData = false;

FlowerPower.discoverAll(function(flowerPower) {

async.series([

function(callback) {
  flowerPower.on('disconnect', function() {
    console.log('disconnected!');
    process.exit(0);
  });
  flowerPower.on('soilMoistureChange', function(soilMoisture) {
    console.log('soil moisture = ' + soilMoisture.toFixed(2) + '%');
  });
  flowerPower.on('calibratedSoilMoistureChange', function(soilMoisture) {
    console.log('calibrated soil moisture = ' + soilMoisture.toFixed(2) + '%');
  });
  console.log('connectAndSetup');
  flowerPower.connectAndSetup(callback);
},
function(callback) {
  flowerPower.readFriendlyName(function(error, friendlyName) {
    console.log('friendly name = ' + friendlyName);
    callback();
  });
},
function(callback) {
  flowerPower.readSystemId(function(error, systemId) {
    console.log('system id = ' + systemId);
    callback();
  });
},
function(callback) {
  flowerPower.readSoilMoisture(function(error, soilMoisture) {
    console.log('soil moisture = ' + soilMoisture.toFixed(2) + '%');
    callback();
  });
},
function(callback) {
  flowerPower.disconnect(callback);
}

]);
});

Hi @elitistphoenix

If you want get soil moisture level from several flower power, delete the line: process.exit(0);.
Bluetooth Low Energie can connect on multiple device in the same time.
Your program found two flower power:

connectAndSetup
connectAndSetup

And if one of them have to disconnect, the program exit, you have no more data.

I think you can simply:

FlowerPower.discoverAll(function(flowerPower) {

  async.series([

    function(callback) {
      flowerPower.on('disconnect', function() {
        // console.log(flowerPower.uuid + ': disconnected!');
      });
      flowerPower.connectAndSetup(callback);
    },

    function(callback) {
      flowerPower.readSoilMoisture(function(error, soilMoisture) {
        console.log(flowerPower.uuid + ': soil moisture = ' + soilMoisture.toFixed(2) + '%');
        callback();
      });
    },
    flowerPower.disconnect.bind(flowerPower)
  ]);
});

It will be print only the soil moisture and the uuid of the flower power.

Bruno

@BrunoSautron - THANK YOU!!

I’ll just use another cron job to kill it after 2 minutes when it’s read them all in.

1 Like