2021-02-21 16:35:18 +00:00
# include <Arduino.h>
# include <Homie.h>
/*
* Wemos d1 mini
* Flash Size : 4 M ( 1 M SPIFFS )
*/
//Upload config: platformio run --target uploadfs
2021-02-18 21:10:39 +00:00
2021-02-22 18:34:18 +00:00
2021-02-18 21:10:39 +00:00
# include "HX711.h"
2021-02-22 18:34:18 +00:00
# define SCALE_CALIBRATION 23805 //calibrated with 2.25kg weight. devide adc reading by calibration weight (in kg) to get this value (or other way around)
2021-02-18 21:10:39 +00:00
// HX711 circuit wiring
const int LOADCELL_DOUT_PIN = D2 ;
const int LOADCELL_SCK_PIN = D3 ;
2021-02-21 16:35:18 +00:00
const int PIN_SELFENABLE = D1 ;
2021-02-18 21:10:39 +00:00
HX711 scale ;
2021-02-21 16:35:18 +00:00
# define MEASURE_INTERVAL 100 //ms
# define READING_FILTER_SIZE 40 //latency is about READING_FILTER_SIZE/2*MEASURE_INTERVAL
float weight_read [ READING_FILTER_SIZE ] = { 0 } ;
uint8_t weight_read_pos = 0 ;
# define MEANVALUECOUNT 4 //0<= meanvaluecount < READING_FILTER_SIZE/2
float weight_tare = 0 ; //minimal filtered weight
# define MIN_WEIGHT_DIFFERENCE 50 //minimum weight
float weight_max = 0 ; //max filtered weight
bool weight_sent = false ;
unsigned long weight_sent_time = 0 ;
# define MAXONTIME 60000*2 //turn off after ms
# define FW_NAME "scale"
# define FW_VERSION "0.0.1"
void loopHandler ( ) ;
HomieNode scaleNode ( " weight " , " Scale " , " scale " ) ; //paramters: topic, $name, $type
int sort_desc ( const void * cmp1 , const void * cmp2 ) ;
float getFilteredWeight ( ) ;
float getWeightSpread ( ) ;
void sendWeight ( float w ) ;
2021-02-22 18:34:18 +00:00
bool cmdHandler ( const HomieRange & range , const String & value ) ;
void powerOff ( ) ;
2021-02-21 16:35:18 +00:00
2021-02-18 21:10:39 +00:00
void setup ( ) {
2021-02-21 16:35:18 +00:00
pinMode ( PIN_SELFENABLE , OUTPUT ) ;
digitalWrite ( PIN_SELFENABLE , HIGH ) ;
pinMode ( LED_BUILTIN , OUTPUT ) ;
digitalWrite ( LED_BUILTIN , HIGH ) ;
2021-02-18 21:10:39 +00:00
Serial . begin ( 115200 ) ;
2021-02-21 16:35:18 +00:00
Homie . disableResetTrigger ( ) ; //disable config reset if pin 1 (D3) is low on startup
Homie_setFirmware ( FW_NAME , FW_VERSION ) ;
Homie_setBrand ( FW_NAME ) ;
Homie . setLoopFunction ( loopHandler ) ;
scaleNode . advertise ( " human " ) ;
scaleNode . advertise ( " spread " ) ;
scaleNode . advertise ( " raw " ) ;
scaleNode . advertise ( " max " ) ;
2021-02-22 18:34:18 +00:00
scaleNode . advertise ( " CMD " ) . settable ( cmdHandler ) ; //function inputHandler gets called on new message on topic/input/set
2021-02-21 16:35:18 +00:00
Homie . setup ( ) ;
2021-02-18 21:10:39 +00:00
scale . begin ( LOADCELL_DOUT_PIN , LOADCELL_SCK_PIN ) ;
2021-02-18 21:28:46 +00:00
//calibration
Serial . println ( " setup " ) ;
2021-02-22 18:34:18 +00:00
scale . set_scale ( SCALE_CALIBRATION ) ;
2021-02-18 21:28:46 +00:00
delay ( 500 ) ;
scale . tare ( ) ;
delay ( 2000 ) ;
Serial . println ( " tared. measuring... " ) ;
//after this taring put known weight on scale and get value from scale.get_units(10). then devide this value by the weight and use this number for set_scale(NUMBER)
/*
Serial . println ( " Before setting up the scale: " ) ;
Serial . print ( " read: \t \t " ) ;
Serial . println ( scale . read ( ) ) ; // print a raw reading from the ADC
Serial . print ( " read average: \t \t " ) ;
Serial . println ( scale . read_average ( 20 ) ) ; // print the average of 20 readings from the ADC
Serial . print ( " get value: \t \t " ) ;
Serial . println ( scale . get_value ( 5 ) ) ; // print the average of 5 readings from the ADC minus the tare weight (not set yet)
Serial . print ( " get units: \t \t " ) ;
Serial . println ( scale . get_units ( 5 ) , 1 ) ; // print the average of 5 readings from the ADC minus tare weight (not set) divided
// by the SCALE parameter (not set yet)
scale . set_scale ( 2280.f ) ; // this value is obtained by calibrating the scale with known weights; see the README for details
scale . tare ( ) ; // reset the scale to 0
Serial . println ( " After setting up the scale: " ) ;
Serial . print ( " read: \t \t " ) ;
Serial . println ( scale . read ( ) ) ; // print a raw reading from the ADC
Serial . print ( " read average: \t \t " ) ;
Serial . println ( scale . read_average ( 20 ) ) ; // print the average of 20 readings from the ADC
Serial . print ( " get value: \t \t " ) ;
Serial . println ( scale . get_value ( 5 ) ) ; // print the average of 5 readings from the ADC minus the tare weight, set with tare()
Serial . print ( " get units: \t \t " ) ;
Serial . println ( scale . get_units ( 5 ) , 1 ) ; // print the average of 5 readings from the ADC minus tare weight, divided
// by the SCALE parameter set with set_scale
Serial . println ( " Readings: " ) ;
*/
2021-02-18 21:10:39 +00:00
}
void loop ( ) {
2021-02-21 16:35:18 +00:00
Homie . loop ( ) ;
}
2021-02-18 21:10:39 +00:00
2021-02-18 21:28:46 +00:00
2021-02-21 16:35:18 +00:00
void loopHandler ( ) {
unsigned long loopmillis = millis ( ) ;
static unsigned long last_measure = 0 ;
if ( loopmillis > last_measure + MEASURE_INTERVAL ) {
last_measure = loopmillis ;
Serial . print ( " reading= " ) ;
float weight_current = 0 ;
if ( scale . wait_ready_timeout ( 1000 ) ) { //for non blocking mode
weight_read_pos + + ;
weight_read_pos % = READING_FILTER_SIZE ;
weight_current = scale . get_units ( 1 ) ;
weight_read [ weight_read_pos ] = weight_current ; //one reading takes 91ms
} else {
Serial . println ( " HX711 not found. " ) ;
2021-02-22 18:34:18 +00:00
scaleNode . setProperty ( " cmd " ) . send ( " HX711 not found " ) ; //can be done in main loop
2021-02-21 16:35:18 +00:00
}
float weight_filtered = getFilteredWeight ( ) ;
float spread = getWeightSpread ( ) ;
Serial . println ( weight_current ) ;
Serial . print ( " spread= " ) ; Serial . println ( spread , 3 ) ;
char charBuf [ 10 ] ;
dtostrf ( weight_current , 4 , 3 , charBuf ) ;
scaleNode . setProperty ( " raw " ) . send ( charBuf ) ;
dtostrf ( spread , 4 , 3 , charBuf ) ;
scaleNode . setProperty ( " spread " ) . send ( charBuf ) ;
# define MAXSPREAD_TARE 0.1 //in kg, for tare can be lower than for measuring
if ( spread < MAXSPREAD_TARE ) { //if reading is stable
if ( weight_filtered < weight_tare ) { //new min
weight_tare = weight_filtered ;
Serial . print ( " new tare= " ) ; Serial . println ( weight_tare , 3 ) ;
}
}
# define MAXSPREAD_MEASURE 0.5 //in kg
if ( spread < MAXSPREAD_MEASURE ) { //if reading is stable
if ( weight_filtered > weight_max ) { //new max
weight_max = weight_filtered ;
Serial . print ( " new max= " ) ; Serial . println ( weight_max , 3 ) ;
}
}
dtostrf ( weight_max - weight_tare , 4 , 3 , charBuf ) ;
scaleNode . setProperty ( " max " ) . send ( charBuf ) ; //filtered and auto tared
if ( ! weight_sent ) {
if ( weight_max - weight_tare > MIN_WEIGHT_DIFFERENCE ) {
sendWeight ( weight_max - weight_tare ) ;
}
}
}
# define STAYONTIME_AFTER_SENT 5000
if ( millis ( ) > MAXONTIME | | ( weight_sent & & millis ( ) > weight_sent_time + STAYONTIME_AFTER_SENT ) ) {
2021-02-22 18:34:18 +00:00
powerOff ( ) ;
2021-02-21 16:35:18 +00:00
}
2021-02-18 21:10:39 +00:00
2021-02-18 21:28:46 +00:00
/*
scale . power_down ( ) ; // put the ADC in sleep mode
delay ( 5000 ) ;
scale . power_up ( ) ; */
2021-02-18 21:10:39 +00:00
2021-02-21 16:35:18 +00:00
}
int sort_desc ( const void * cmp1 , const void * cmp2 ) //compare function for qsort
{
float a = * ( ( float * ) cmp1 ) ;
float b = * ( ( float * ) cmp2 ) ;
return a > b ? - 1 : ( a < b ? 1 : 0 ) ;
}
float getFilteredWeight ( ) {
float copied_values [ READING_FILTER_SIZE ] ;
for ( int i = 0 ; i < READING_FILTER_SIZE ; i + + ) {
copied_values [ i ] = weight_read [ i ] ; //TODO: maybe some value filtering/selection here
}
float copied_values_length = sizeof ( copied_values ) / sizeof ( copied_values [ 0 ] ) ;
qsort ( copied_values , copied_values_length , sizeof ( copied_values [ 0 ] ) , sort_desc ) ;
float mean = copied_values [ READING_FILTER_SIZE / 2 ] ;
for ( uint8_t i = 1 ; i < = MEANVALUECOUNT ; i + + ) {
mean + = copied_values [ READING_FILTER_SIZE / 2 - i ] + copied_values [ READING_FILTER_SIZE / 2 + i ] ; //add two values around center
}
mean / = ( 1 + MEANVALUECOUNT * 2 ) ;
return mean ;
}
float getWeightSpread ( ) { //absolute difference between lowest and highest value in buffer
float copied_values [ READING_FILTER_SIZE ] ;
for ( int i = 0 ; i < READING_FILTER_SIZE ; i + + ) {
copied_values [ i ] = weight_read [ i ] ; //TODO: maybe some value filtering/selection here
}
float copied_values_length = sizeof ( copied_values ) / sizeof ( copied_values [ 0 ] ) ;
qsort ( copied_values , copied_values_length , sizeof ( copied_values [ 0 ] ) , sort_desc ) ;
float diff = copied_values [ 0 ] - copied_values [ READING_FILTER_SIZE - 1 ] ;
if ( diff < 0 ) { //abs for float
diff * = - 1 ;
}
return diff ;
}
void sendWeight ( float w ) {
char charBuf [ 10 ] ;
dtostrf ( w , 4 , 3 , charBuf ) ;
scaleNode . setProperty ( " human " ) . send ( charBuf ) ;
weight_sent = true ;
weight_sent_time = millis ( ) ;
Serial . print ( " Weight sent= " ) ; Serial . println ( w , 3 ) ;
2021-02-22 18:34:18 +00:00
}
bool cmdHandler ( const HomieRange & range , const String & value ) {
if ( range . isRange ) {
return false ; //if range is given but index is not in allowed range
}
Homie . getLogger ( ) < < " cmd " < < " : " < < value < < endl ;
//boolean value
if ( value = = " reset " ) {
if ( scale . wait_ready_timeout ( 1000 ) ) { //for non blocking mode
scale . set_scale ( 0 ) ;
scale . tare ( ) ;
scaleNode . setProperty ( " cmd " ) . send ( " tared " ) ;
} else {
Serial . println ( " HX711 not found. " ) ;
scaleNode . setProperty ( " cmd " ) . send ( " HX711 not found " ) ;
}
} if ( value = = " adc " ) {
if ( scale . wait_ready_timeout ( 1000 ) ) { //for non blocking mode
scaleNode . setProperty ( " cmd " ) . send ( " adc= " + scale . read_average ( 20 ) ) ;
} else {
Serial . println ( " HX711 not found. " ) ;
scaleNode . setProperty ( " cmd " ) . send ( " HX711 not found " ) ;
}
} if ( value = = " off " ) {
powerOff ( ) ;
scaleNode . setProperty ( " cmd " ) . send ( " shutting down " ) ;
} else {
Homie . getLogger ( ) < < " cmd not recognized " < < endl ;
return false ;
}
return true ;
}
void powerOff ( ) {
Serial . println ( " Turning Off " ) ;
Serial . flush ( ) ;
delay ( 100 ) ;
digitalWrite ( PIN_SELFENABLE , LOW ) ;
2021-02-18 21:10:39 +00:00
}