Skip to content

feat: implement dust sensor (SDS011 - UART interface)#3245

Draft
ctrlVnt wants to merge 36 commits into
fossasia:mainfrom
ctrlVnt:dust-sensor
Draft

feat: implement dust sensor (SDS011 - UART interface)#3245
ctrlVnt wants to merge 36 commits into
fossasia:mainfrom
ctrlVnt:dust-sensor

Conversation

@ctrlVnt

@ctrlVnt ctrlVnt commented May 20, 2026

Copy link
Copy Markdown
Contributor

Fixes #2988

Changes

  • Added dust sensor

Note
I couldn't test on PSLab pocket because I still don't have it for now but I'm inspiring to others sensors for the design and to Kotlin version to logic (comunication hardware in initializeSensors() method)

Screenshots / Recordings

Screencast.From.2026-05-20.13-46-29.webm

Checklist:

  • No hard coding: I have used values from constants.dart or localization files instead of hard-coded values.
  • No end of file edits: No modifications done at end of resource files.
  • Code reformatting: I have formatted the code using dart format or the IDE formatter.
  • Code analysis: My code passes checks run in flutter analyze and tests run in flutter test.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @ctrlVnt, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@ctrlVnt ctrlVnt changed the title Dust sensor Feat: implement dust sensor May 20, 2026
@ctrlVnt ctrlVnt requested a review from marcnause May 20, 2026 11:55
@ctrlVnt ctrlVnt changed the title Feat: implement dust sensor feat: implement dust sensor May 20, 2026
@ctrlVnt ctrlVnt requested review from bhavjsh and rahul31124 May 20, 2026 12:01
@marcnause

marcnause commented May 20, 2026

Copy link
Copy Markdown
Contributor

I just noticed that I do not own all sensors which were supported by the old version of the app. I ordered an SDS011 to review this PR.

@marcnause

Copy link
Copy Markdown
Contributor

See #3246 regarding the failing Windows build.

@github-actions

github-actions Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

Build Status

Build successful. APKs to test: https://github.com/fossasia/pslab-app/actions/runs/28704449805/artifacts/8081252966.

Screenshots

Android Screenshots
iPhone Screenshots
iPad Screenshots

@rahul31124 rahul31124 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @ctrlVnt,

How will you test this? Please refer to the legacy app to see how it was implemented there
Link:
https://github.com/fossasia/pslab-app/blob/app/pslab-development-release.apk

@marcnause

Copy link
Copy Markdown
Contributor

I never used this feature in the old app, so I am not sure if it ever worked. The sensor comes with a USB dongle and I am curious if it can also be connected to the PSLab at all.

@ctrlVnt

ctrlVnt commented May 24, 2026

Copy link
Copy Markdown
Contributor Author

Hello @ctrlVnt,

How will you test this? Please refer to the legacy app to see how it was implemented there
Link:
https://github.com/fossasia/pslab-app/blob/app/pslab-development-release.apk

Hi @rahul31124,

I can't test for now because I still don't have PSLab pocket but I copied the same logic of sound meter for UI and, if it doesn't work, we need to implement a support for the sensor. Now I use .getVoltage("CH1", 1) method to read sensor but I don't expect that it works (copyed from Kotlin version this too)

@ctrlVnt

ctrlVnt commented May 24, 2026

Copy link
Copy Markdown
Contributor Author

Can be interesting to test in old version if it worked well

@marcnause

Copy link
Copy Markdown
Contributor

I am still waiting for the sensor...

@rahul31124 rahul31124 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @ctrlVnt,You have implemented the SDS011 dust sensor, which is UART-based, but the dust sensor we had earlier was the DSM-501A PWM based, @marcnause which one should we use?🙂

@marcnause

Copy link
Copy Markdown
Contributor

The sensor I have is the SDS011. It supports both UART and PWM. I omitted UART in an earlier message in this thread because I forgot that we had a usable UART interface on the PSLab. 🤦

The SDS011 is more expensive than the DSM-501A. Maybe we could support both at some point? We should limit this PR to one sensor though. Since I have the SDS011 and the current implementation matches it, I'd suggest we continue with it.

photo of a SDS011 sensor

@ctrlVnt ctrlVnt changed the title feat: implement dust sensor feat: implement dust sensor (SDS011 - UART interface) Jun 15, 2026
@marcnause

Copy link
Copy Markdown
Contributor

@ctrlVnt I think the data sheet I mentioned earlier only contains half the the truth. There is also a "Laser Dust Sensor Control Protocol"-document: https://learn.watterott.com/sensors/sds011/sds011_protocol.pdf

The factory default is continuous measurement mode after startup, but I think we should set the desired mode (see chapter 5 of the document) in case somebody uses a sensor with a different configuration (I am not sure if the working period is persistent).

Also I noticed that the data frame is mentioned to be set to 8 data bit, no parity, one stop bit (8N1) in the document. Our communication layer does not support setting this, but the PSLab-Python library does: https://github.com/fossasia/pslab-python/blob/main/pslab/bus/uart.py#L107C9-L107C23

I tried adding it to our communication layer, but it did not make a difference. (Maybe I made a mistake.)

I am not sure how to continue. You don't have the sensor, I don't have the time to really dig into the subject. How about me sending you the sensor and you send it back to me for the review of the PR once you are done? The sensor is relatively expensive (> 25 €) and even though I thought I ordered it from Germany, it was dropshipped to me from China which took longer than I expected. I guess that sending it to you from Germany would be fairly fast.

If you think this is a reasonable idea, please contact me via Telegram and provide me with an address I can send it to. I will pay for the return postage.

@marcnause

Copy link
Copy Markdown
Contributor

The sensor is on its way!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Dust Sensor (SDS011 via UART2) instrument to the Flutter PSLab app, including a dedicated screen/UI, configuration UI, and the underlying UART2 communication support needed to fetch and visualize PM readings.

Changes:

  • Introduces Dust Sensor UI (screen + card) with live PM2.5 visualization, playback support, and data export flow.
  • Adds Dust Sensor state/config providers and a persisted configuration model.
  • Extends the PSLab communication layer with UART2 configuration/status/read helpers and wires the new instrument into routing + localization.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
lib/view/widgets/dust_sensor_card.dart New UI card for displaying PM2.5 and air quality status with a gauge.
lib/view/instruments_screen.dart Adds Dust Sensor entry to the instruments list.
lib/view/dust_sensor_screen.dart New Dust Sensor main screen with charting, guide, logging/export, and config navigation.
lib/view/dust_sensor_config_screen.dart New configuration screen for dust sensor settings.
lib/providers/dust_sensor_state_provider.dart New state provider handling UART2 reads, chart data, recording, and playback.
lib/providers/dust_sensor_config_provider.dart New persisted config provider using SharedPreferences.
lib/models/dust_sensor_config.dart New config model (update period, limits, active sensor, location logging).
lib/main.dart Registers the /dustsensor route.
lib/l10n/app_en.arb Adds dust sensor intro/config strings and air-quality labels.
lib/communication/science_lab.dart Adds UART2 configuration/status/read methods required for SDS011.
lib/communication/packet_handler.dart Fixes an incorrect log message in getByte().

Comment on lines +100 to +108
void initializeSensors({Function(String)? onError}) async {
onSensorError = onError;

try {
ScienceLab scienceLab = getIt.get<ScienceLab>();

await scienceLab.configureUART(baudRate: 9600);
await Future.delayed(const Duration(milliseconds: 500));

Comment on lines +109 to +116
_startTime = DateTime.now().millisecondsSinceEpoch / 1000.0;

_timeTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
_currentTime =
(DateTime.now().millisecondsSinceEpoch / 1000.0) - _startTime;
_updateData();
notifyListeners();
});
Comment on lines +60 to +62
void setConfigProvider(DustSensorConfigProvider configProvider) {
_configProvider = configProvider;
}
Comment on lines +156 to +159
void _handleSensorError(dynamic error) {
onSensorError?.call("Unable to access SDS011 sensor via UART");
logger.e("Dust sensor error: $error");
}
Comment on lines +64 to +66
_updatePeriodController.text =
provider.config.updatePeriod.toString();
_highLimitController.text = provider.config.highLimit.toString();
Comment on lines +91 to +101
ConfigInputItem(
title: appLocalizations.highLimit,
value:
"${provider.config.highLimit} ${appLocalizations.ppm}",
controller: _highLimitController,
hint: appLocalizations.dustHighLimitHint,
onChanged: (value) {
try {
double highLimit = double.parse(value);
if (highLimit > 5.0 || highLimit < 0.0) {
throw const FormatException();
Comment thread lib/l10n/app_en.arb
"manualMode": "Manual Mode",
"frequencyChange": "Stop playback to change frequency.",
"playBackStop": "Playback stopped",
"dustSensorIntro": "Connect pins according to pin diagram and start measuring. Power up the sensor using VCC pin in PSLab and connect data pin to CH1. Make sure the ground wire is connected to one of the GND pins in PSLab.",
Comment on lines +1396 to +1402
Future<void> configureUART({required int baudRate}) async {
if (!isConnected()) return;

try {
mPacketHandler.sendByte(mCommandsProto.uart2);
mPacketHandler.sendByte(mCommandsProto.setBaud);
mPacketHandler.sendInt(baudRate);
Comment thread lib/view/dust_sensor_screen.dart
Comment thread lib/view/dust_sensor_screen.dart Outdated
@ctrlVnt ctrlVnt marked this pull request as draft June 27, 2026 11:23
@marcnause

Copy link
Copy Markdown
Contributor

I just had a look at the old logs I posted previously and I noticed, that I received timeouts. fossasia/pslab-firmware#206 also mentions timeouts.

@rahul31124 Is it possible that we have the same or a similar problem here?

@ctrlVnt Does using Rahul's changed firmware (Google Drive link in #3395) make a difference?

@ctrlVnt

ctrlVnt commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

@ctrlVnt Does using Rahul's changed firmware (Google Drive link in #3395) make a difference?

Actually I didn't tested, this can make a difference, thank you!

@marcnause

Copy link
Copy Markdown
Contributor

Actually I didn't tested, this can make a difference, thank you!

I didn't expect you to, sorry if it came across that way. I just wanted to jot down the idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Dust Sensor instrument

7 participants