Untitled
Anonymous
plain_text
02/03/2026 6:39 AM
10.2 KB
11
Indexable
class ESP32WeightReader:
"""Kelas untuk membaca berat dari file yang dibuat oleh ESP32 - FIXED"""
def __init__(self, data_file=ESP32_DATA_FILE):
self.data_file = data_file
self.last_weight = 0.0
self.last_read_time = 0
self.read_interval = ESP32_READ_INTERVAL
self.weight_buffer = []
self.BUFFER_SIZE = 10
self.invalid_count = 0
self.max_invalid = 5
self.status = "INIT"
self.status_color = (255, 165, 0)
os.makedirs(os.path.dirname(data_file), exist_ok=True)
self.load_last_weight()
print(f"[ESP32] Initialized - reading from: {data_file}")
def read_weight_file(self):
"""Baca berat dari file - FIXED untuk handle newline"""
try:
# Cek apakah file ada
if not os.path.exists(self.data_file):
with open(self.data_file, 'w') as f:
f.write("0.000") # TANPA newline di akhir
print(f"[ESP32] File tidak ditemukan, dibuat baru: {self.data_file}")
self.status = "NO FILE"
self.status_color = (255, 0, 0)
return 0.0
# Baca isi file
with open(self.data_file, 'r', encoding='utf-8') as f:
content = f.read()
# DEBUG: Tampilkan content mentah
print(f"[ESP32_RAW] Raw content: '{repr(content)}'")
# Bersihkan content: hapus semua whitespace, newline, carriage return
content = content.strip() # Hapus whitespace di awal/akhir
content = content.replace('\n', '').replace('\r', '').replace('\t', '').replace(' ', '')
# DEBUG: Tampilkan content setelah dibersihkan
print(f"[ESP32_CLEAN] Clean content: '{content}'")
if not content:
self.status = "EMPTY"
self.status_color = (255, 165, 0)
return 0.0
# Coba parsing dengan beberapa metode
# Metode 1: Coba langsung float
try:
weight = float(content)
print(f"[ESP32_PARSE] Direct float: {weight:.3f}kg")
self.status = "OK"
self.status_color = (0, 255, 0)
return weight
except ValueError:
pass
# Metode 2: Cari angka pertama dalam string
# Regex untuk mencari angka (termasuk negatif dan desimal)
import re
numbers = re.findall(r'[-+]?\d*\.\d+|[-+]?\d+', content)
if numbers:
try:
weight = float(numbers[0])
print(f"[ESP32_PARSE] Regex found: {weight:.3f}kg (from: {numbers})")
self.status = "OK"
self.status_color = (0, 255, 0)
return weight
except ValueError:
pass
# Metode 3: Coba split dan ambil bagian pertama
parts = content.split()
if parts:
try:
weight = float(parts[0])
print(f"[ESP32_PARSE] Split found: {weight:.3f}kg (from: {parts})")
self.status = "OK"
self.status_color = (0, 255, 0)
return weight
except ValueError:
pass
print(f"[ESP32_PARSE] No valid number found in: '{content}'")
self.status = "PARSE ERR"
self.status_color = (255, 0, 0)
return self.last_weight
except Exception as e:
print(f"[ESP32] Error reading weight file: {e}")
import traceback
traceback.print_exc()
self.status = "READ ERR"
self.status_color = (255, 0, 0)
return self.last_weight
def get_weight_kg(self):
"""Dapatkan berat dalam kg - FIXED dengan validasi"""
current_time = time.time()
# Rate limiting
if current_time - self.last_read_time < self.read_interval:
return self.last_weight
self.last_read_time = current_time
# Baca dari file
raw_weight = self.read_weight_file()
# DEBUG: Tampilkan raw weight
print(f"[ESP32_DEBUG] Raw weight from file: {raw_weight:.3f}kg")
# Validasi: cek range yang wajar
if raw_weight < -5.0 or raw_weight > 100.0: # Range wajar untuk timbangan
print(f"[ESP32_VALID] Weight out of range: {raw_weight:.3f}kg, using last: {self.last_weight:.3f}kg")
return self.last_weight
# Validasi: jika perubahan terlalu drastis (> 2kg dalam 100ms)
if self.last_weight != 0:
weight_diff = abs(raw_weight - self.last_weight)
if weight_diff > 2.0:
print(f"[ESP32_VALID] Suspicious jump: {self.last_weight:.3f} -> {raw_weight:.3f}kg (diff: {weight_diff:.3f})")
self.invalid_count += 1
if self.invalid_count >= self.max_invalid:
print("[ESP32_VALID] Too many invalid readings")
return self.last_weight
else:
# Gunakan rata-rata untuk smooth
raw_weight = (raw_weight + self.last_weight * 3) / 4
print(f"[ESP32_VALID] Smoothed to: {raw_weight:.3f}kg")
else:
self.invalid_count = 0
# Update buffer untuk moving average
self.weight_buffer.append(raw_weight)
if len(self.weight_buffer) > self.BUFFER_SIZE:
self.weight_buffer.pop(0)
# Hitung smoothed weight
if len(self.weight_buffer) >= 3:
smoothed_weight = sum(self.weight_buffer) / len(self.weight_buffer)
else:
smoothed_weight = raw_weight
# Dead zone: jika < 5 gram, anggap 0
if abs(smoothed_weight) < 0.005:
smoothed_weight = 0.0
# Update last weight
self.last_weight = smoothed_weight
# Simpan ke cache
self.save_last_weight(smoothed_weight)
print(f"[ESP32_FINAL] Final weight: {smoothed_weight:.3f}kg")
return round(smoothed_weight, 3)
def save_last_weight(self, weight):
"""Simpan berat terakhir ke file cache"""
try:
cache_data = {
"weight_kg": weight,
"timestamp": time.time(),
"date": str(datetime.now())
}
with open(LAST_WEIGHT_FILE, 'w', encoding='utf-8') as f:
json.dump(cache_data, f, indent=2)
except Exception as e:
print(f"[ESP32] Error saving cache: {e}")
def load_last_weight(self):
"""Load berat terakhir dari cache"""
try:
if os.path.exists(LAST_WEIGHT_FILE):
with open(LAST_WEIGHT_FILE, 'r', encoding='utf-8') as f:
cache_data = json.load(f)
self.last_weight = cache_data.get("weight_kg", 0.0)
print(f"[ESP32] Loaded cached weight: {self.last_weight:.3f}kg")
return True
except:
pass
return False
def force_read(self):
"""Paksa baca ulang file (debug)"""
self.last_read_time = 0 # Reset timer
return self.get_weight_kg()Editor is loading...
Leave a Comment