Quick Start Guide
Get started building TelemetryOS applications in minutes
Quick Start Guide
Get started building TelemetryOS applications in minutes.
Prerequisites
- Node.js 18+
- npm or pnpm
- Basic knowledge of JavaScript/TypeScript and web development
Installation
CLI Tool Installation
The TelemetryOS CLI scaffolds and runs applications locally. CLI installation enables rapid application generation with best practices built in:
# Install CLI globally
npm install -g @telemetryos/cli
# Create new application
tos init my-weather-app
# Navigate to project
cd my-weather-app
# Install dependencies
npm install
# Start local development server
tos serveManual SDK Installation
The SDK integrates into existing projects through npm installation:
npm install @telemetryos/sdkYour First Application
Project Structure
A TelemetryOS application typically has this structure:
my-weather-app/
├── src/
│ ├── views/
│ │ ├── Render.tsx # Display content (runs on devices)
│ │ └── Settings.tsx # Configuration UI (runs in admin)
│ ├── App.tsx # Routing between views
│ └── index.tsx # Entry point
├── telemetry.config.json # Application configuration
├── package.json
├── vite.config.ts
└── tsconfig.json
Configuration File
Create telemetry.config.json in your project root:
{
"name": "my-weather-app",
"version": "1.0.0",
"mountPoints": {
"render": "/render",
"settings": "/settings"
},
"devServer": {
"runCommand": "vite --port 3000",
"url": "http://localhost:3000"
}
}Key Fields:
name- Application identifier (must matchconfigure()call)version- Application version (semver format)mountPoints- URL paths for render and settings viewsdevServer- Local development server configuration
Settings View
Create the configuration UI that runs in the admin portal:
src/views/Settings.tsx:
import { useEffect, useState } from 'react';
import { configure, store } from '@telemetryos/sdk';
configure('my-weather-app');
export function Settings() {
const [city, setCity] = useState('');
// Load current city on mount
useEffect(() => {
store().instance.get<string>('city').then(savedCity => {
if (savedCity) setCity(savedCity);
});
}, []);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
await store().instance.set('city', city);
alert('Settings saved!');
};
return (
<div className="settings">
<h2>Weather App Settings</h2>
<form onSubmit={handleSubmit}>
<label>
City:
<input
type="text"
value={city}
onChange={(e) => setCity(e.target.value)}
placeholder="Enter city name"
/>
</label>
<button type="submit">Save</button>
</form>
</div>
);
}Render View
Create the display content that runs on devices:
src/views/Render.tsx:
import { useEffect, useState } from 'react';
import { configure, store } from '@telemetryos/sdk';
configure('my-weather-app');
export function Render() {
const [city, setCity] = useState<string | null>(null);
const [weather, setWeather] = useState<any>(null);
useEffect(() => {
// Subscribe to city changes
const handler = (newCity: string) => {
setCity(newCity);
fetchWeather(newCity);
};
store().instance.subscribe('city', handler);
// Load initial value
store().instance.get<string>('city').then(savedCity => {
if (savedCity) {
setCity(savedCity);
fetchWeather(savedCity);
}
});
return () => {
store().instance.unsubscribe('city', handler);
};
}, []);
const fetchWeather = async (cityName: string) => {
// Fetch weather data for the city
// Implementation details omitted for brevity
setWeather({ temp: '72°F', condition: 'Sunny' });
};
if (!city) {
return <div className="render">Please configure a city in settings</div>;
}
return (
<div className="render">
<h1>{city}</h1>
{weather && (
<>
<div className="temp">{weather.temp}</div>
<div className="condition">{weather.condition}</div>
</>
)}
</div>
);
}Routing
Set up routing between views based on URL path:
src/App.tsx:
import { Settings } from './views/Settings';
import { Render } from './views/Render';
export function App() {
const path = window.location.pathname;
if (path === '/settings') {
return <Settings />;
}
if (path === '/render') {
return <Render />;
}
return <div>404 - Not Found</div>;
}src/index.tsx:
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { App } from './App';
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>
);Local Development
Development Server
The CLI development server (tos serve) provides local application testing:
tos serveThe development server:
- Reads
telemetry.config.jsonfor configuration - Executes
devServer.runCommand(typically Vite or webpack-dev-server) - Opens development UI at the configured URL
- Provides simulated TelemetryOS environment for testing
Mount Point Testing
Mount points are accessible at configured URLs:
- Settings: http://localhost:3000/settings
- Render: http://localhost:3000/render
The development server provides mock SDK responses, enabling testing without TelemetryOS platform connection.
SDK Initialization
Always call configure() early in your application lifecycle:
import { configure } from '@telemetryos/sdk';
// Must match name in telemetry.config.json
configure('my-weather-app');Important: Call configure() once per mount point before using other SDK features.
Communication Between Views
Settings and render views share the same instance storage scope:
// In Settings - save configuration
await store().instance.set('city', 'New York');
// In Render - subscribe to changes
store().instance.subscribe('city', (newCity) => {
console.log('City changed to:', newCity);
});This pattern enables real-time updates when configuration changes.
Error Handling
All SDK operations can throw errors or timeout (30 seconds):
try {
await store().instance.set('key', 'value');
} catch (error) {
console.error('Failed to save:', error);
// Show user-friendly error message
}Deployment Methods
TelemetryOS supports three deployment methods. GitHub integration provides automated Git-to-Screen deployment and is recommended for production workflows.
GitHub Integration
GitHub integration enables automated deployment through repository connection:
# Initialize git and push to GitHub
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/your-org/weather-widget.git
git push -u origin mainStudio repository connection:
- Applications interface provides GitHub integration option
- Repository connection establishes secure access to source code
- Branch selection determines which commits trigger builds
- Platform automatically builds and deploys on every push
Archive Upload
Archive upload supports manual deployment when Git is unavailable:
# Build your application
npm run build
# Create zip archive
cd dist
zip -r ../my-weather-app.zip .Archive upload workflow:
- Applications interface provides archive upload option
- Platform extracts archive contents
- Build scripts execute using configured parameters
- Applications deploy after successful builds
Archive uploads require manual updates for code changes; automatic builds are not available.
Generic Git Repository
Generic Git repository support accommodates GitLab, Bitbucket, or self-hosted Git services:
- Code pushes to Git hosting service
- Studio generic Git repository option accepts repository URLs
- Deploy keys provide secure repository access
- Webhook configuration enables automatic builds
Post-Deployment
After successful deployment:
- Applications appear in Studio Applications list
- Applications add to playlists as resizable regions
- Settings interface accessible through playlist application selection
- Playlist assignment deploys applications to devices
Next Steps
- Mount Points - Understand render, settings, workers, containers
- Storage Methods - Learn all four storage scopes
- Configuration - Complete telemetry.config.json reference
- Code Examples - See complete working applications
Common Patterns
Loading Initial Data
useEffect(() => {
store().instance.get<string>('setting').then(value => {
if (value) setSettingValue(value);
});
}, []);Real-Time Updates
useEffect(() => {
const handler = (newValue: any) => {
setMyState(newValue);
};
store().instance.subscribe('key', handler);
return () => {
store().instance.unsubscribe('key', handler);
};
}, []);Error Recovery
try {
const data = await media().getAllByTag('marketing');
displayMedia(data);
} catch (error) {
// Provide fallback
displayPlaceholder();
}Troubleshooting
SDK Configuration Errors:
configure('app-name')must be called before using SDK functions- Application name must match
telemetry.config.jsonname field
Timeout Errors:
- Network connectivity issues cause SDK operation timeouts
- Retry logic handles transient failures for critical operations
- Fallback content ensures displays never show blank states
Storage Persistence Issues:
- Storage scope selection (application/instance/device/shared) determines data visibility
- Successful
set()responses confirm data persistence - Scope mismatches prevent data access across components
Mount Point Loading Issues:
- Mount point paths in
telemetry.config.jsonmust match application routing - Browser console errors indicate routing or configuration problems
Development Best Practices
Early Initialization: configure() calls occur at application startup before SDK usage.
Subscription Pattern: Subscriptions provide real-time updates; polling is unnecessary and inefficient.
Error Handling: All async SDK operations can fail; error handling ensures graceful degradation.
Local Testing: CLI development server (tos serve) enables rapid iteration without platform deployment.
Type Safety: TypeScript definitions catch configuration and API usage errors during development.
Updated 5 days ago