Calibrate your scale before using all the code. Remove these lines from the code and enable logging in DEBUG mode. This is how we will receive raw data. Record the weight without a load, copy the numbers from the logs as they are, then take a 500 gram load and put it on the scales, record the numbers. Write all these numbers into a linear filter
An example of a filter, where -169085 is the raw value and this is the value without a weight on the scale, so I indicated that this value has a weight of 0 grams, and the value -92230 was displayed in the logs after I set the weight to 500 grams and then indicated that this value has a weight of 500 grams
If the readings are unstable, fluctuate frequently and strongly, then replace the HX711 controller with a working one, otherwise the filters will not help. I personally encountered this myself and wasted a lot of time setting up filters. If the HX711 controller is working properly, the scale readings at rest may change slightly and this is normal, but they do not fluctuate greatly and constantly. In this case, an additional filter will help, for example the median filter, which can stabilize the scale readings. Read more in the ESPHome documentation
Sensitive strain gauges with 1 gram accuracy. You can find them in electronic kitchen scales with round legs. We take any kitchen scale with round legs, not sticks. This can be easily understood if you turn the scales over. I took these kitchen scales
The platform was designed in FreeCAD. Download FreeCAD available here. I have included 3 files, two STL files and one for FreeCAD where you can edit if necessary. I designed it so that the strain gauges would hold tightly and made the clips in the form of an arc, which is why the strain gauges hardly fall into place; you need to pry them off with a thin flat-head screwdriver, but they stand clearly and it will be very difficult to remove them without damaging the case.
What you need to assemble a rotating bowl with scales
Sensitive strain gauges with 1 gram accuracy. You can find them in electronic kitchen scales with round legs. We take any kitchen scale with round legs, not sticks. This can be easily understood if you turn the scales over. I took these kitchen scales
We take power from the automatic feeder itself, which produces 5V and 1A, which will be enough to power the entire feeder completely. For full operation of the feeder, a current of up to 800mA is required.
The bowl consists of several parts. Made to save printing time and filament in case the part breaks and to avoid printing the entire bowl again. Read about bearing 6814 2RS (61814) SLZ below
The orange circle is bearing 6814 2RS (61814) SLZ, which is inserted into a round platform under a steel bowl (blue in the screenshot). To prevent the steel bowl from sliding on the top of the platform, I recommend spraying it with liquid rubber. Provides excellent grip on the bowl
Thanks to this post I learned about an interesting ESP32 board with a compartment for an 18650 battery and this can be used in an auto feeder as a backup power supply in case the electricity goes out, and also monitor the battery charge level. I bought an ESP32 with a battery here
I used a divider of two 220 kOhm resistors and lowered the voltage to 2.4 V to fall into the range from 150 to 2450. I took it from the table in the documentation esp32 on ADC voltage.
Next, I measured the voltage with a multimeter at full discharged and charged battery and used a filter, which obtained correct voltage readings with a small error of -/+ 0.05V. The fully measured battery had a voltage of 4.175V, and in the sensor the value was 2.151, this is a figure in parrots and I converted it to the real value thus 4.175/2.151 = 1.940957694095769 ~ 1.941
filters:
- multiply: 1.941
Working code. If you have your own thoughts on this matter, I will only be glad if you post your version of the code.
#####################################################################################
###################################### Variables ####################################
substitutions:
name: feeder-pettix-s36
#####################################################################################
################################# Basic configuration ###############################
esphome:
name: $name
friendly_name: Feeder Pettix S36
comment: Feeder Pettix S36
#####################################################################################
####################################### Platform ####################################
esp32:
board: esp32dev
framework:
type: arduino
#####################################################################################
################################ WiFi and access point ##############################
#Wi-Fi credentials for connecting the board to the home network
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: off
reboot_timeout: 5min
#If there is no connection with WiFi, then the access point will rise
ap:
ssid: ESP Feeder Pettix S36
password: !secret ap_esp_password
ap_timeout: 1 min
manual_ip:
static_ip: 192.168.4.1
gateway: 192.168.4.1
subnet: 255.255.255.0
#The mdns component forces the node to announce itself on the local network using the DNS Multicast Protocol (mDNS), by default for mDNS disabled: false
mdns:
disabled: false
#The captive portal component in ESPHome is a backup mechanism in case the connection to the configured Wi-Fi fails
captive_portal:
#Web server
web_server:
port: 80
#Logging
logger:
baud_rate: 0
#Enable Home Assistant API
api:
#Over-the-Air Update (OTA)
ota:
password: "esphome"
#####################################################################################
################################## Sensor ###########################################
sensor:
#ADC sensor for battery level sensor
- platform: adc
name: ADC
icon: mdi:flash
id: idADC
pin: GPIO32
attenuation: 11db
update_interval: 60s
accuracy_decimals: 3
internal: false #Hide - true \show - false
#Battery level sensor
- platform: copy
name: Battery Level
icon: mdi:battery
id: idBatteryLevel
source_id: idADC
unit_of_measurement: '%'
accuracy_decimals: 0
filters:
- calibrate_linear:
#The battery voltage should not be lower than 3V and higher than 4.2V. To get into the range 0-2500 you need to use a divider to reduce the voltage to 2.4V and specify attenuation: 11db
#A divider of resistors 220 and 220 kom is used
- 1.545 -> 0
- 2.151 -> 100
#Battery voltage sensor. The readings are reliable with an error
- platform: copy
name: "Battery Voltage"
icon: mdi:flash
id: idBatteryVoltage
source_id: idADC
accuracy_decimals: 3
filters:
- multiply: 1.941
#####################################################################################
##################################### Text sensor ###################################
text_sensor:
#IP
- platform: wifi_info
ip_address:
name: IP
icon: mdi:ip-network
#ESPHome Version
- platform: version
name: "ESPHome Version"
hide_timestamp: true
#Uptime
- platform: template
name: "Uptime"
icon: mdi:clock-start
id: idUptimeESP
entity_category: diagnostic
- platform: template
name: "Time"
icon: mdi:clock-digital
id: idTime
update_interval: 10s
lambda: |-
auto time_text = id(homeassistant_time).now().strftime("%H:%M:%S / %d-%m-%Y");
return { time_text };
#Remaining time until charging 100%
- name: "Charging time up to 100%"
id: idChargingTime
platform: template
update_interval: 10s
lambda: |-
auto time = id(homeassistant_time).now();
if (!time.is_valid())
{
return {};
}
auto diff = time.timestamp;
if (id(idBatteryLevel).state != 100)
{
auto result = ((diff / id(idBatteryLevel).state) * (100 - id(idBatteryLevel).state)) / 86400;
result = result < 0 ? 0 : result;
auto hours = static_cast<int>(result) / 3600;
auto minutes = (static_cast<int>(result) % 3600) / 60;
return to_string(hours) + "h " + to_string(minutes) + "m";
}
else
{
auto result = diff / 86400;
result = result < 0 ? 0 : result;
auto hours = static_cast<int>(result) / 3600;
auto minutes = (static_cast<int>(result) % 3600) / 60;
return to_string(hours) + "h " + to_string(minutes) + "m";
}
#Remaining time until discharge at 0%
- name: "Discharge time to 0%"
id: idDischargeTime
platform: template
update_interval: 10s
lambda: |-
auto time = id(homeassistant_time).now();
if (!time.is_valid())
{
return {};
}
auto diff = time.timestamp;
if (id(idBatteryLevel).state != 0)
{
auto result = ((diff / (100 - id(idBatteryLevel).state)) * id(idBatteryLevel).state) / 86400;
result = result < 0 ? 0 : result;
auto hours = static_cast<int>(result) / 3600;
auto minutes = (static_cast<int>(result) % 3600) / 60;
return to_string(hours) + "h " + to_string(minutes) + "m";
}
else
{
auto result = diff / 86400;
result = result < 0 ? 0 : result;
auto hours = static_cast<int>(result) / 3600;
auto minutes = (static_cast<int>(result) % 3600) / 60;
return to_string(hours) + "h " + to_string(minutes) + "m";
}
#####################################################################################
####################################### Button ######################################
button:
- platform: restart
name: "Restart"
icon: mdi:restart
#####################################################################################
######################################## Time #######################################
time:
- platform: homeassistant
id: homeassistant_time