Thank you for your interest in contributing to the BACnet Flutter plugin! This document provides guidelines and instructions for contributing.
By participating in this project, you agree to maintain a respectful and inclusive environment for all contributors.
Before creating an issue, please:
- Check if the issue already exists in GitHub Issues
- Collect relevant information (Flutter version, platform, error messages)
- Create a minimal reproduction case if possible
Issue Template:
**Description:**
Brief description of the issue
**Steps to Reproduce:**
1. Step one
2. Step two
3. ...
**Expected Behavior:**
What you expected to happen
**Actual Behavior:**
What actually happened
**Environment:**
- Flutter version: X.X.X
- Dart version: X.X.X
- Platform: Windows/Linux/macOS/Android/iOS
- Plugin version: X.X.X
**Additional Context:**
Error messages, screenshots, code snippetsFeature suggestions are welcome! Please:
- Check existing issues and discussions
- Clearly describe the use case
- Explain how it aligns with BACnet protocol standards
- Provide examples if possible
We love pull requests! Here's the process:
-
Fork and Clone
git clone https://github.com/YOUR_USERNAME/bacnet_plugin.git cd bacnet_plugin -
Create a Branch
git checkout -b feature/my-feature # or git checkout -b fix/my-bugfix -
Make Changes
- Follow the code style guidelines (see below)
- Add tests for new functionality
- Update documentation as needed
- Run code generation if modifying models
-
Test Your Changes
# Run static analysis flutter analyze # Format code dart format . # Run tests flutter test # Run integration tests cd example flutter test integration_test/
-
Generate Code (if you modified models with @JsonSerializable)
dart run build_runner build --delete-conflicting-outputs
-
Commit Changes
git add . git commit -m "feat: add new feature" # or git commit -m "fix: resolve issue #123"
Use conventional commit messages:
feat:New featuresfix:Bug fixesdocs:Documentation changesstyle:Code style changes (formatting)refactor:Code refactoringtest:Adding or updating testschore:Maintenance tasks
-
Push and Create PR
git push origin feature/my-feature
Then create a Pull Request on GitHub.
This project follows the Flutter/Dart style guide from .agent/rules/rules.md.
General:
- Use single quotes for strings
- Prefer
constconstructors when possible - Line length: 80 characters
- Use meaningful, descriptive names
- No abbreviations
Classes:
- Use
PascalCasefor class names - Use
camelCasefor methods and variables - Use
snake_casefor filenames - Make classes immutable when possible
- Use
@immutableannotation - Implement
copyWith()for data classes
Documentation:
- Add dartdoc (
///) to all public APIs - Include examples in documentation
- Document parameters and return values
- Explain complex logic with inline comments
Functions:
- Keep functions short (< 20 lines ideally)
- Single responsibility principle
- Use
async/awaitfor asynchronous operations - Proper error handling with try-catch
Imports:
- Organize imports: dart, flutter, package, relative
- Use
showorhideto limit imports when appropriate
Example:
/// Represents a BACnet device with its metadata.
///
/// Example:
/// ```dart
/// final device = BacnetDevice(
/// deviceId: 1234,
/// name: 'Building Controller',
/// ipAddress: '192.168.1.100',
/// );
/// ```
@immutable
class BacnetDevice {
/// Creates a BACnet device.
const BacnetDevice({
required this.deviceId,
required this.name,
required this.ipAddress,
});
/// The unique device instance number.
final int deviceId;
/// The human-readable device name.
final String name;
/// The IP address of the device.
final String ipAddress;
/// Creates a copy of this device with updated values.
BacnetDevice copyWith({
int? deviceId,
String? name,
String? ipAddress,
}) {
return BacnetDevice(
deviceId: deviceId ?? this.deviceId,
name: name ?? this.name,
ipAddress: ipAddress ?? this.ipAddress,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is BacnetDevice && other.deviceId == deviceId;
}
@override
int get hashCode => deviceId.hashCode;
}Place unit tests in test/ directory:
import 'package:bacnet_plugin/bacnet_plugin.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('BacnetObject', () {
test('creates object with required fields', () {
final obj = BacnetObject(
type: BacnetObjectType.analogInput,
instance: 1,
);
expect(obj.type, equals(BacnetObjectType.analogInput));
expect(obj.instance, equals(1));
});
test('copyWith updates only specified fields', () {
final obj = BacnetObject(type: 0, instance: 1);
final updated = obj.copyWith(instance: 2);
expect(updated.type, equals(0));
expect(updated.instance, equals(2));
});
});
}Place integration tests in example/integration_test/:
import 'package:bacnet_plugin/bacnet_plugin.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Client can start and stop', (tester) async {
final client = BacnetClient();
await client.start();
await Future.delayed(Duration(seconds: 1));
client.dispose();
expect(true, isTrue); // Test passed
});
}Aim for:
- 80%+ code coverage for public APIs
- 100% coverage for data models
- Integration tests for key user flows
When adding new features:
- Update README.md - Add examples and usage instructions
- Add dartdoc comments - Document all public APIs
- Update CHANGELOG.md - Describe changes in version
- Consider adding examples - In
example/directory
When implementing BACnet features:
- Follow ASHRAE Standard 135
- Use official BACnet terminology
- Reference the standard in comments
- Add protocol constants to appropriate constant files
- Test against real BACnet devices when possible
Example:
/// BACnet Acknowledge-Alarm service (ASHRAE 135-2020, Section 15.2).
Future<void> acknowledgeAlarm(...) async {
// Implementation
}Models use json_serializable for JSON support:
-
Add annotations:
@immutable @JsonSerializable() class MyModel { // ... factory MyModel.fromJson(Map<String, dynamic> json) => _$MyModelFromJson(json); Map<String, dynamic> toJson() => _$MyModelToJson(this); }
-
Add part directive:
part 'my_model.g.dart';
-
Run code generation:
dart run build_runner build --delete-conflicting-outputs
-
Commit generated files - Include
.g.dartfiles in commits
If modifying native BACnet stack code:
- Update header files in
native/include/ - Update bindings configuration in
ffigen.yaml - Regenerate FFI bindings:
dart run ffigen --config ffigen.yaml
- Test on all supported platforms
- Document any platform-specific behavior
For maintainers:
- Update version in
pubspec.yaml - Update
CHANGELOG.mdwith changes - Run all tests and checks
- Create git tag:
git tag v0.0.2 - Push tag:
git push origin v0.0.2 - Create GitHub release with notes
- Publish to pub.dev:
flutter pub publish
- Open a discussion on GitHub Discussions
- Ask in issues if related to a specific problem
- Check existing documentation and examples first
Your contributions make this project better for everyone. Thank you for taking the time to contribute!
Happy Coding! 🚀