Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions lib/communication/sensors/mlx90614.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import 'dart:async';
import '../peripherals/i2c.dart';

class MLX90614 {
final I2C i2c;
// The default I2C address for MLX90614 is 0x5A
static const int address = 0x5A;

// Register addresses
static const int ambientTempReg = 0x06;
static const int objectTempReg = 0x07;

MLX90614(this.i2c);

/// Reads the Ambient (Room) Temperature
Future<double> getAmbientTemperature() async {
return _readTemperature(ambientTempReg);
}

/// Reads the Object (Target) Temperature
Future<double> getObjectTemperature() async {
return _readTemperature(objectTempReg);
}

/// Helper function to handle the math
Future<double> _readTemperature(int reg) async {
// FIX: Use readBulk instead of read.
// Arguments: (Device Address, Register Address, Bytes to Read)
List<int> data = await i2c.readBulk(address, reg, 2);

if (data.length < 2) {
throw Exception("Failed to read temperature from MLX90614");
}

// MLX90614 sends LSB first, then MSB.
int lsb = data[0];
int msb = data[1];

// Combine the bytes: (MSB << 8) | LSB
int rawValue = (msb << 8) | lsb;

// Formula from datasheet:
// The sensor returns temperature in Kelvin * 50.
// Multiply by 0.02 to get Kelvin.
// Subtract 273.15 to convert Kelvin to Celsius.
double tempCelsius = (rawValue * 0.02) - 273.15;

return tempCelsius;
}
}
5 changes: 5 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:pslab/l10n/app_localizations.dart';
import 'package:pslab/providers/board_state_provider.dart';
import 'package:pslab/providers/locator.dart';
import 'package:pslab/providers/settings_config_provider.dart';
import 'package:pslab/providers/mlx90614_provider.dart'; // <--- 1. IMPORT ADDED
import 'package:pslab/view/accelerometer_screen.dart';
import 'package:pslab/view/barometer_screen.dart';
import 'package:pslab/view/connect_device_screen.dart';
Expand Down Expand Up @@ -42,6 +43,10 @@ void main() {
ChangeNotifierProvider<BoardStateProvider>(
create: (context) => getIt<BoardStateProvider>(),
),
// <--- 2. PROVIDER ADDED
ChangeNotifierProvider<MLX90614Provider>(
create: (context) => getIt<MLX90614Provider>(),
),
],
child: const MyApp(),
),
Expand Down
4 changes: 4 additions & 0 deletions lib/providers/locator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:pslab/communication/science_lab.dart';
import 'package:pslab/communication/socket_client.dart';
import 'package:pslab/others/science_lab_common.dart';
import 'package:pslab/providers/board_state_provider.dart';
import 'package:pslab/providers/mlx90614_provider.dart'; // <--- 1. IMPORT ADDED

final GetIt getIt = GetIt.instance;

Expand All @@ -29,6 +30,9 @@ void setupLocator() {
getIt.registerLazySingleton<ScienceLab>(
() => getIt.get<ScienceLabCommon>().getScienceLab());
getIt.registerLazySingleton<BoardStateProvider>(() => BoardStateProvider());

// <--- 2. REGISTRATION ADDED
getIt.registerLazySingleton<MLX90614Provider>(() => MLX90614Provider());
}

void registerAppLocalizations(AppLocalizations appLocalizations) {
Expand Down
49 changes: 49 additions & 0 deletions lib/providers/mlx90614_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import '../communication/sensors/mlx90614.dart';
import '../communication/peripherals/i2c.dart';

class MLX90614Provider with ChangeNotifier {
MLX90614? _sensor;
bool isWorking = false;

// This sensor provides two values
double ambientTemp = 0.0; // Room temperature
double objectTemp = 0.0; // Target temperature

// Initialize the sensor with the I2C connection
Future<void> init(I2C i2c) async {
_sensor ??= MLX90614(i2c);
}

// Start the loop to read data
Future<void> startDataLog() async {
if (_sensor == null) return;

// Check if loop is already running to prevent duplicates
if (isWorking) return;

isWorking = true;
notifyListeners();

while (isWorking) {
try {
// Read both values safely
ambientTemp = await _sensor!.getAmbientTemperature();
objectTemp = await _sensor!.getObjectTemperature();
notifyListeners();
} catch (e) {
debugPrint("Error reading MLX90614: $e");
}

// Wait 1 second before next read
await Future.delayed(const Duration(milliseconds: 1000));
}
}

// Stop the loop
void stopDataLog() {
isWorking = false;
notifyListeners();
}
}
125 changes: 125 additions & 0 deletions lib/view/mlx90614_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:pslab/communication/science_lab.dart';
import 'package:pslab/communication/peripherals/i2c.dart';
import 'package:pslab/providers/locator.dart';
import '../providers/mlx90614_provider.dart';

class MLX90614Screen extends StatefulWidget {
const MLX90614Screen({super.key});

@override
State<MLX90614Screen> createState() => _MLX90614ScreenState();
}

class _MLX90614ScreenState extends State<MLX90614Screen> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;

final provider = Provider.of<MLX90614Provider>(context, listen: false);

// Get the ScienceLab instance via the locator
final scienceLab = getIt<ScienceLab>();

if (scienceLab.isConnected()) {
// Create I2C helper and init
I2C i2c = I2C(scienceLab.mPacketHandler);
provider.init(i2c);
provider.startDataLog();
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Device not connected')),
);
}
});
}

@override
void dispose() {
// Stop the data loop when leaving the screen
if (mounted) {
Provider.of<MLX90614Provider>(context, listen: false).stopDataLog();
}
super.dispose();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('MLX90614 Sensor'),
),
body: Consumer<MLX90614Provider>(
builder: (context, provider, child) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
// Card 1: Object Temperature (What you are pointing at)
_buildSensorCard(
title: "Object Temperature",
value: provider.objectTemp.toStringAsFixed(2),
unit: "°C",
icon: Icons.thermostat_auto, // Icon representing target
color: Colors.deepOrangeAccent,
),
const SizedBox(height: 20),

// Card 2: Ambient Temperature (Room temp)
_buildSensorCard(
title: "Ambient Temperature",
value: provider.ambientTemp.toStringAsFixed(2),
unit: "°C",
icon: Icons.home_mini, // Icon representing environment
color: Colors.blueGrey,
),
],
),
);
},
),
);
}

Widget _buildSensorCard({
required String title,
required String value,
required String unit,
required IconData icon,
required Color color,
}) {
return Card(
elevation: 4,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Row(
children: [
Icon(icon, size: 40, color: color),
const SizedBox(width: 20),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title,
style: const TextStyle(fontSize: 16, color: Colors.grey)),
Row(
children: [
Text(value,
style: const TextStyle(
fontSize: 32, fontWeight: FontWeight.bold)),
const SizedBox(width: 5),
Text(unit, style: const TextStyle(fontSize: 20)),
],
),
],
),
),
],
),
),
);
}
}
11 changes: 11 additions & 0 deletions lib/view/sensors_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import 'package:provider/provider.dart';
import 'package:pslab/view/bmp180_screen.dart';
import 'package:pslab/view/ads1115_screen.dart';
import 'package:pslab/view/vl53l0x_screen.dart';
import 'package:pslab/view/mlx90614_screen.dart'; // Keep this one!
import 'package:pslab/view/widgets/common_scaffold_widget.dart';
import '../../providers/board_state_provider.dart';
import '../l10n/app_localizations.dart';
import '../providers/locator.dart';
import '../theme/colors.dart';
import 'apds9960_screen.dart';
// REMOVED: import 'package:pslab/view/sht21_screen.dart'; <-- Causing error

class SensorsScreen extends StatefulWidget {
const SensorsScreen({super.key});
Expand Down Expand Up @@ -229,9 +231,18 @@ class _SensorsScreenState extends State<SensorsScreen> {
break;
case 'APDS9960':
targetScreen = const APDS9960Screen();
break;
case 'VL53L0X':
targetScreen = const VL53L0XScreen();
break;

// Keep ONLY MLX90614 for this PR
case 'MLX90614':
targetScreen = const MLX90614Screen();
break;

// REMOVED: case 'SHT21': ... <-- Causing error

default:
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
Expand Down
2 changes: 2 additions & 0 deletions macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Foundation
import connectivity_plus
import device_info_plus
import file_picker
import geolocator_apple
import package_info_plus
import path_provider_foundation
import share_plus
Expand All @@ -18,6 +19,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
Expand Down
3 changes: 3 additions & 0 deletions windows/flutter/generated_plugin_registrant.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <connectivity_plus/connectivity_plus_windows_plugin.h>
#include <flusbserial/fl_usb_serial_plugin.h>
#include <geolocator_windows/geolocator_windows.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h>
#include <share_plus/share_plus_windows_plugin_c_api.h>
#include <url_launcher_windows/url_launcher_windows.h>
Expand All @@ -17,6 +18,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
FlUsbSerialPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FlUsbSerialPlugin"));
GeolocatorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("GeolocatorWindows"));
PermissionHandlerWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
SharePlusWindowsPluginCApiRegisterWithRegistrar(
Expand Down
1 change: 1 addition & 0 deletions windows/flutter/generated_plugins.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
connectivity_plus
flusbserial
geolocator_windows
permission_handler_windows
share_plus
url_launcher_windows
Expand Down
Loading