drone-mobile-sdk v1.0.2
DroneMobile SDK
DroneMobile SDK is a TypeScript library that provides a seamless interface to interact with the Drone-Mobile API. It leverages modern technologies, including the latest AWS SDK (v3), Bun for building and publishing, and Pino for efficient logging. This SDK simplifies the process of managing your Drone-Mobile account, controlling vehicles, and retrieving vehicle data.
Table of Contents
Features
- AWS SDK v3 Integration: Utilizes the latest AWS SDK for secure and efficient authentication.
- Pino Logging: High-performance logging with configurable levels.
- Bun-Based Build and Publish: Fast bundling and publishing using Bun's powerful tools.
- Comprehensive Testing: Jest-compatible test runner with support for TypeScript.
- TypeScript Support: Strong typing ensures reliability and ease of use.
Installation
Prerequisites
- Node.js: Ensure you have Node.js (v12 or higher) installed.
- Bun: Install Bun by following the official installation guide.
Steps
Clone the Repository
git clone https://github.com/your-username/drone-mobile-sdk.git cd drone-mobile-sdkInstall Dependencies
Using Bun:
bun installThis will install all necessary dependencies, including:
@aws-sdk/client-cognito-identity-providergotpinotypescript(as a dev dependency)@types/node(as a dev dependency)
Configuration
Environment Variables
Create a .env file in the root directory to store your Drone-Mobile credentials securely:
touch .envAdd the following variables to .env:
DRONEMOBILE_USERNAME=your-username
DRONEMOBILE_PASSWORD=your-passwordNote: Ensure .env is added to your .gitignore to prevent committing sensitive information.
Usage
Initialization
First, import the DroneMobile class and initialize it with your credentials.
import DroneMobile from 'drone-mobile-sdk';
const droneMobile = await DroneMobile.create({
username: 'your-username',
password: 'your-password',
});Methods
Login
The SDK automatically handles login during initialization. However, you can manually trigger a login if needed.
await droneMobile.login();Fetch Vehicles
Retrieve a list of all vehicles associated with your account.
const vehicles = await droneMobile.vehicles();
console.log('Vehicles:', vehicles);Options:
interface VehicleOptions {
all?: boolean; // Whether to fetch all vehicles recursively (default: true)
limit?: number; // Maximum number of vehicles to fetch (default: 100)
offset?: number; // Number of vehicles to skip (default: 0)
}Example:
const vehicles = await droneMobile.vehicles({ all: true, limit: 50, offset: 0 });Control Vehicle
Control various aspects of a vehicle using its device_key.
Start Vehicle
const response = await droneMobile.start('vehicle-device-key');
console.log(response); // 'remote_start command was successful!'Stop Vehicle
const response = await droneMobile.stop('vehicle-device-key');
console.log(response); // 'remote_stop command was successful!'Lock Vehicle
const response = await droneMobile.lock('vehicle-device-key');
console.log(response); // 'arm command was successful!'Unlock Vehicle
const response = await droneMobile.unlock('vehicle-device-key');
console.log(response); // 'disarm command was successful!'Open Trunk
const response = await droneMobile.trunk('vehicle-device-key');
console.log(response); // 'trunk command was successful!'AUX Actions
const aux1Response = await droneMobile.aux1('vehicle-device-key');
console.log(aux1Response); // 'remote_aux1 command was successful!'
const aux2Response = await droneMobile.aux2('vehicle-device-key');
console.log(aux2Response); // 'remote_aux2 command was successful!'Get Vehicle Status
Retrieve the current status of a specific vehicle.
const status = await droneMobile.status('vehicle-device-key');
console.log('Vehicle Status:', status);Returns:
An object containing detailed status information about the vehicle.
Get Vehicle Location
Retrieve the current location of a specific vehicle.
const location = await droneMobile.location('vehicle-device-key');
console.log('Vehicle Location:', location);Returns:
An object containing latitude, longitude, speed, and other location-related data.
Full Example
import DroneMobile from 'drone-mobile-sdk';
(async () => {
try {
// Initialize the SDK
const droneMobile = await DroneMobile.create({
username: 'your-username',
password: 'your-password',
});
// Fetch all vehicles
const vehicles = await droneMobile.vehicles();
console.log('Vehicles:', vehicles);
if (vehicles.length === 0) {
console.log('No vehicles found.');
return;
}
const vehicleId = vehicles[0].device_key;
// Start the vehicle
const startResponse = await droneMobile.start(vehicleId);
console.log(startResponse);
// Get vehicle status
const status = await droneMobile.status(vehicleId);
console.log('Vehicle Status:', status);
// Stop the vehicle
const stopResponse = await droneMobile.stop(vehicleId);
console.log(stopResponse);
} catch (error) {
console.error('An error occurred:', error);
}
})();Logging
DroneMobile SDK uses Pino for logging, providing high-performance and configurable logging capabilities.
Configuration
The logger can be configured via environment variables and the logger.ts file.
- Environment Variables:
LOG_LEVEL: Sets the logging level (fatal,error,warn,info,debug,trace). Default isinfo.NODE_ENV: Set toproductionto disable pretty-printing and output logs in JSON format.
Usage
The logger is automatically integrated into the SDK. You can control the verbosity by setting the LOG_LEVEL environment variable.
import logger from './logger';
logger.info('This is an info message');
logger.error('This is an error message');Example Configuration
// logger.ts
import pino from 'pino';
const isProduction = process.env.NODE_ENV === 'production';
const logger = pino({
level: process.env.LOG_LEVEL || 'info',
...(isProduction
? {}
: {
transport: {
target: 'pino-pretty',
options: {
colorize: true,
translateTime: 'yyyy-mm-dd HH:MM:ss',
ignore: 'pid,hostname',
},
},
}),
});
export default logger;Testing
The project uses Bun's built-in Jest-compatible test runner for testing. Tests are written in TypeScript and support features like lifecycle hooks and mocking.
Writing Tests
Tests are located in the tests/ directory and follow the naming patterns:
*.test.ts*_test.ts*.spec.ts*_spec.ts
Example Test
// tests/droneMobile.test.ts
import { expect, test, beforeAll, afterAll } from 'bun:test';
import DroneMobile from '../src/index';
import { ResultsEntity } from '../src/interfaces';
import { config } from 'dotenv';
config();
let droneMobile: DroneMobile;
let vehicleId: string;
beforeAll(async () => {
droneMobile = await DroneMobile.create({
username: process.env.DRONEMOBILE_USERNAME!,
password: process.env.DRONEMOBILE_PASSWORD!,
});
const vehicles = await droneMobile.vehicles();
if (vehicles.length > 0) {
vehicleId = vehicles[0].device_key;
} else {
throw new Error('No vehicles found for this account.');
}
});
afterAll(() => {
// Clean up resources if needed
});
test('DroneMobile instance should be created and logged in', () => {
expect(droneMobile).toBeDefined();
expect(droneMobile.sessionInfo.accessToken).not.toBeNull();
});
test('Should fetch vehicles', async () => {
const vehicles = await droneMobile.vehicles();
expect(vehicles).toBeDefined();
expect(vehicles.length).toBeGreaterThan(0);
expect(vehicles[0]).toHaveProperty('device_key');
});
test('Should start the vehicle', async () => {
const response = await droneMobile.start(vehicleId);
expect(response).toBe('remote_start command was successful!');
});
test('Should stop the vehicle', async () => {
const response = await droneMobile.stop(vehicleId);
expect(response).toBe('remote_stop command was successful!');
});
test('Should lock the vehicle', async () => {
const response = await droneMobile.lock(vehicleId);
expect(response).toBe('arm command was successful!');
});
test('Should unlock the vehicle', async () => {
const response = await droneMobile.unlock(vehicleId);
expect(response).toBe('disarm command was successful!');
});
test('Should get vehicle status', async () => {
const status = await droneMobile.status(vehicleId);
expect(status).toBeDefined();
expect(status?.device_key).toBe(vehicleId);
});
test('Should handle invalid command', async () => {
try {
await (droneMobile as any).sendCommand(vehicleId, 'invalid_command');
} catch (error) {
expect(error).toBeDefined();
expect((error as Error).message).toBe('Command failed');
}
});
test('Should get vehicle location', async () => {
const location = await droneMobile.location(vehicleId);
expect(location).toBeDefined();
// Add more assertions based on the expected structure of the location data
});Running Tests
Execute all tests with:
bun testAdditional Test Runner Flags:
Run Specific Tests:
bun test --test-name-pattern 'Should start the vehicle'Watch Mode:
bun test --watchUpdate Snapshots:
bun test --update-snapshots
Building and Publishing
The project uses Bun for building and publishing the package to npm. Below are the steps to compile your TypeScript code into a single JavaScript file and publish the package.
Step 1: Build Your Package
Bun's built-in bundler can compile and bundle your TypeScript files into a single JavaScript file.
bun build src/index.ts --outdir dist --target bun --no-splitting --minifyExplanation:
src/index.ts: Entry point of your application.--outdir dist: Output directory for the bundled file.--target bun: Specifies Bun as the target environment.--no-splitting: Disables code splitting to ensure a single output file.--minify: Minifies the output code for optimized performance.
Alternative Configuration with bunfig.toml:
# bunfig.toml
[build]
entrypoints = ["./src/index.ts"]
outdir = "./dist"
target = "bun"
no-splitting = true
minify = trueNow, you can simply run:
bun buildStep 2: Generate Type Definitions
While Bun's bundler doesn't generate .d.ts files, you can use the TypeScript compiler to generate them.
Install TypeScript:
bun add -d typescriptCreate or Update
tsconfig.json:Ensure your
tsconfig.jsonincludes the following:{ "compilerOptions": { "declaration": true, "emitDeclarationOnly": true, "outDir": "dist", "rootDir": "src", "strict": true, "skipLibCheck": true, "esModuleInterop": true }, "include": ["src/**/*"] }Generate Type Definitions:
bun x tscThis will generate
.d.tsfiles in thedistdirectory.
Step 3: Update package.json
Ensure your package.json points to the correct entry points.
{
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": ["dist"],
"scripts": {
"build": "bun build",
"type:build": "bun x tsc",
"prepublishOnly": "bun run build && bun run type:build",
"test": "bun test"
}
}Step 4: Publish to npm
Log In to npm:
bun pm loginFollow the prompts to authenticate.
Publish Your Package:
bun publishNote: If your package is scoped (e.g.,
@your-username/package-name), you might need to set the access level to public:bun publish --access publicVerify the Publish:
After publishing, verify your package on npm by searching for your package name.
Step 5: Test Your Package Locally (Optional)
Before publishing, it's good practice to test your package locally.
Pack Your Package:
bun pm packThis creates a
package.tgzfile.Install the Packed Package in a Test Project:
bun add ../path-to-your-package/package.tgzVerify Functionality:
Create a simple project to import and use your SDK to ensure everything works as expected.
Contributing
Contributions are welcome! Please follow these steps to contribute to the DroneMobile SDK:
Fork the Repository
Create a Feature Branch
git checkout -b feature/your-feature-nameCommit Your Changes
git commit -m "Add your feature"Push to the Branch
git push origin feature/your-feature-nameOpen a Pull Request
Describe your changes and submit the pull request for review.
Guidelines
- Code Quality: Ensure your code follows TypeScript best practices and is well-documented.
- Testing: Write tests for new features and ensure existing tests pass.
- Documentation: Update the README and other documentation as needed.
License
This project is licensed under the MIT License.
Contact
For any questions, issues, or feature requests, please open an issue on GitHub
Happy Coding!