#include #include /* * Wemos d1 mini * Flash Size: 4M (1M SPIFFS) */ //Upload config: platformio run --target uploadfs #include "HX711.h" //#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) #define SCALE_CALIBRATION 23960 //8 club mate 0.5L bottles weight 7.097kg. scale returns units=340090 with 16 bottles -> 340090/(2*7.097kg) = 23960 // HX711 circuit wiring const int LOADCELL_DOUT_PIN = D2; const int LOADCELL_SCK_PIN = D3; const int PIN_SELFENABLE = D1; HX711 scale; float weight_current=0; //last weight reading #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 MQTT_SENDINTERVALL 500 //ms unsigned long last_mqtt_send=0; bool livesend=false; //if true, sends continuous data over mqtt #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); bool cmdHandler(const HomieRange& range, const String& value); void powerOff(); void setup() { pinMode(PIN_SELFENABLE,OUTPUT); digitalWrite(PIN_SELFENABLE, HIGH); pinMode(LED_BUILTIN,OUTPUT); digitalWrite(LED_BUILTIN, HIGH); Serial.begin(115200); 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("cmd").settable(cmdHandler); //function inputHandler gets called on new message on topic/input/set scaleNode.advertise("human"); scaleNode.advertise("spread"); scaleNode.advertise("raw"); scaleNode.advertise("max"); Homie.setup(); scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN); //calibration Serial.println("setup"); scale.set_scale(SCALE_CALIBRATION); 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:"); */ } void loop() { Homie.loop(); } void loopHandler() { unsigned long loopmillis=millis(); static unsigned long last_measure=0; if (loopmillis>last_measure+MEASURE_INTERVAL) { last_measure=loopmillis; Serial.print("reading="); 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."); scaleNode.setProperty("cmd").send("HX711 not found"); //can be done in main loop } float weight_filtered=getFilteredWeight(); float spread=getWeightSpread(); Serial.println(weight_current); Serial.print("spread="); Serial.println(spread,3); #define MAXSPREAD_TARE 0.1 //in kg, for tare can be lower than for measuring if (spread MAXONTIME || (weight_sent && millis()>weight_sent_time+STAYONTIME_AFTER_SENT)) { powerOff(); } /* scale.power_down(); // put the ADC in sleep mode delay(5000); scale.power_up();*/ } 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