Calendar Data Export Research
Issue: #1995 Related: #1832 - Graph API Integration Status: ✅ Implemented Date: 2025-11-27 Implementation Date: 2025-11-29
Overview
User needs access to calendar data from Teams for Linux to process externally (e.g., convert to org-mode). This research investigates how to expose calendar data with minimal internal logic.
Problem Statement
User wants to:
- Access their Teams calendar data programmatically
- Process it externally (org-mode conversion, etc.)
- Avoid maintaining separate authentication scripts (2FA expires daily)
Key insight: Since they log into Teams for Linux daily anyway, the app can expose calendar data using existing authentication.
Current State
✅ Already Implemented
Teams for Linux has Graph API integration (Phase 1 complete):
- GraphApiClient in
app/graphApi/ - Calendar endpoints functional:
GET /me/calendar/events- All eventsGET /me/calendar/calendarView- Date range filtered
- IPC channels available:
graph-api-get-calendar-eventsgraph-api-get-calendar-view
User can already access calendar data today via IPC calls (just needs documentation).
Recommended Architecture
Philosophy: Minimal Internal Logic
What Teams for Linux should do:
- ✅ Expose calendar data via MQTT command
- ✅ Return raw Graph API JSON
- ✅ React to
get-calendarcommand
What Teams for Linux should NOT do:
- ❌ Format conversion (org-mode, CSV, etc.)
- ❌ Internal scheduling/polling
- ❌ Complex data transformation
- ❌ File management logic
Let the user handle: All formatting, scheduling, and processing externally.
Architectural Constraints
Per ADR-006:
- ❌ Cannot add CLI action commands (e.g.,
teams-for-linux --get-calendar)- Conflicts with meeting URL positional arguments
- Would require fragile pre-parsing
- High risk of breaking existing functionality
Chosen approach:
- ✅ MQTT commands (already used for actions like toggle-mute, toggle-video, etc.)
Implementation: MQTT Command
Decision: MQTT command approach (leverages existing MQTT infrastructure per MQTT Commands Implementation).
User triggers export via MQTT command:
# User sends command to get calendar with start/end dates
mosquitto_pub -h localhost -t teams/command -m '{
"action": "get-calendar",
"startDate": "2025-11-27T00:00:00Z",
"endDate": "2025-12-04T23:59:59Z"
}'
Teams publishes calendar data to response topic:
# Teams publishes to teams/calendar topic
# User subscribes and pipes to their processor
mosquitto_sub -h localhost -t teams/calendar | python3 ~/to_orgmode.py
Architecture:
Implementation:
// In app/index.js - Extend existing mqttClient 'command' event listener
mqttClient.on('command', async (command) => {
// ... existing command handlers (toggle-mute, toggle-video, etc.)
if (command.action === 'get-calendar') {
// Validate parameters
const { startDate, endDate } = command;
if (!startDate || !endDate) {
console.error('[MQTT] get-calendar requires startDate and endDate');
return;
}
// Fetch from Graph API
const result = await graphApiClient.getCalendarView(startDate, endDate);
// Publish raw Graph API JSON to dedicated topic
if (result.success) {
mqttClient.publish('teams/calendar', JSON.stringify(result));
} else {
console.error('[MQTT] Failed to get calendar:', result.error);
}
}
});
User workflow:
# 1. User creates script to request calendar
#!/bin/bash
START_DATE=$(date -I)
END_DATE=$(date -I -d "+7 days")
mosquitto_pub -h localhost -t teams/command -m "{
\"action\":\"get-calendar\",
\"startDate\":\"${START_DATE}T00:00:00Z\",
\"endDate\":\"${END_DATE}T23:59:59Z\"
}"
# 2. User subscribes and processes
mosquitto_sub -h localhost -t teams/calendar -C 1 | python3 ~/to_orgmode.py > calendar.org
# 3. User schedules with cron
0 6 * * * /home/user/scripts/fetch-calendar.sh
Pros:
- ✅ Follows established MQTT pattern (ADR-006, ADR-007)
- ✅ Minimal code changes (~20 lines)
- ✅ Integrates with home automation
- ✅ Event-driven (no internal scheduling)
- ✅ User controls everything externally
Cons:
- ⚠️ Requires MQTT broker (but many users already have one)
- ⚠️ Slightly more setup than direct IPC
Estimated effort: 2-3 hours
Data Format
Return exactly what Graph API returns:
{
"success": true,
"data": {
"value": [
{
"id": "AAMkAGI1...",
"subject": "Team Standup",
"start": {
"dateTime": "2025-11-27T10:00:00.0000000",
"timeZone": "UTC"
},
"end": {
"dateTime": "2025-11-27T10:30:00.0000000",
"timeZone": "UTC"
},
"location": {
"displayName": "Teams Meeting"
},
"organizer": {
"emailAddress": {
"name": "John Doe",
"address": "john@example.com"
}
},
"attendees": [...],
"bodyPreview": "Meeting description...",
"onlineMeeting": {
"joinUrl": "https://teams.microsoft.com/l/meetup/..."
}
}
]
}
}
User converts externally with their own script (Python, shell, whatever).
Implementation Steps
✅ Completed Implementation (2025-11-29):
- ✅ Added
get-calendarcommand to MQTT command handler (app/mqtt/index.js) - ✅ Implemented command validation for startDate and endDate parameters
- ✅ Integrated Graph API client to fetch calendar data (
app/index.js) - ✅ Added generic
publish()method to MQTTClient for calendar data publishing - ✅ Published raw Graph API JSON to
teams/calendartopic - ✅ Documented MQTT workflow in MQTT Integration Guide
Files Modified:
app/mqtt/index.js- Addedget-calendarto allowed actions and genericpublish()methodapp/index.js- Added get-calendar command handler with Graph API integrationdocs-site/docs/mqtt-integration.md- Added Calendar Data Export section
Implementation Risk
Low risk:
- ✅ Minimal code changes (~20 lines for MQTT)
- ✅ Uses existing Graph API client
- ✅ Uses existing MQTT infrastructure
- ✅ No complex logic
- ✅ User controls everything
Success Criteria
- User can retrieve calendar data as JSON via MQTT command
- Data includes all Graph API fields
- User can process output with their own tools
- No internal formatting/transformation logic
- No internal scheduling (user controls when to fetch)
References
- Issue #1995
- ADR-006: CLI Argument Parsing - Why CLI commands are rejected
- ADR-007: Embedded MQTT Broker - MQTT architecture decisions
- MQTT Commands Implementation - Existing MQTT command pattern
- Microsoft Graph Calendar API
- Existing Graph API Integration