Category: Aviation

AnalyticsAviationMicrosoft Fabric

Bringing Real‑Time Intelligence to Airport Data Streams (Type-B Messages) – Part 2: Setting It Up in Microsoft Fabric

In Part 1, I covered the architecture, the event model, and why airport baggage tracking makes such a compelling real-time analytics scenario. In this post, I want to get hands-on and walk through actually setting this up inside Microsoft Fabric — from creating the workspace artifacts all the way through to running the simulator and querying live events.

Let’s get into it.

Prerequisites

Before you start, you’ll need:

  • Microsoft Fabric workspace with the Real-Time Intelligence workload enabled (F2 or higher capacity, or a Fabric trial)
  • An Azure Event Hubs namespace with a hub (or you can use Fabric’s built-in custom endpoint in Eventstream — more on that below)
  • The Baggage Handling Simulator cloned locally, and Python 3.10+ was installed

If you want to follow along with Azure Event Hubs as the source, a Basic-tier namespace is fine for dev/test. If you’re going direct to Fabric Eventstream, you won’t need Event Hubs at all.

Architecture Overview

Step 1: Create the Fabric Workspace Artifacts

Start by creating a new workspace if you don’t already have one. I created on called “Airport Operations Demo”. Open up your Fabric workspace, and you’ll need to create four main artifacts:

  1. Eventhouse (your KQL database)
  2. Eventstream (ingestion and routing)
  3. KQL Queryset (ad-hoc queries and saved analytics)
  4. Real-Time Dashboard (live visualization)

Create the Eventhouse

From the Fabric workspace, click New → Eventhouse. Give it a name like Airport-Eventhouse. This creates an Eventhouse and a default KQL database inside it.

Once provisioned, open the Eventhouse and navigate to the KQL database. This is where we’ll define the table schemas.

Step 2: Create the Table Schema

We’ll use a Bronze / Silver / Gold medallion structure inside the KQL database. Bronze tables hold raw events exactly as ingested. Silver tables hold cleaned and enriched data. Gold tables hold pre-aggregated views.

NOTE: Due to the number of schema objects, I’m going to be showing a subset across each section below. Please go here to see the rest of the KQL scripts to be applied: https://github.com/calloncampbell/BaggageHandling-TypeB-Simulator/blob/main/kql

Open the Explore your data pane in the KQL database and run the following to create the Bronze tables:

// Bronze: raw airport events
.create table airport_events (
id: string,
source: string,
specversion: string,
type: string,
datacontenttype: string,
dataschema: string,
subject: string,
['time']: datetime,
data: dynamic,
seriesclock: datetime
)
.alter table airport_events policy streamingingestion enable
// Bronze: raw flight operational events
.create table typeb_flight_events (
id: string,
source: string,
specversion: string,
type: string,
datacontenttype: string,
dataschema: string,
subject: string,
['time']: datetime,
data: dynamic,
seriesclock: datetime
)
.alter table typeb_flight_events policy streamingingestion enable
// Bronze: event tables
.create table ['Airport.Passenger.Checkin_v1']
(
___id : string,
___source : string,
___type : string,
___time : datetime,
___subject : string,
flightId : string,
flightNumber : string,
airline : string,
origin : string,
destination : string,
departureUtc : string,
paxId : string,
name : string
)

Ingestion Mapping

When events arrive as JSON via Eventstream, you’ll want an ingestion mapping so the raw JSON gets parsed correctly into the table columns:

// Ingestion mapping for airport events
.create-or-alter table airport_events ingestion json mapping "airport_events_mapping"
```
[
{
"column": "id",
"path": "$.id",
"datatype": "string",
"transform": null
},
{
"column": "source",
"path": "$.source",
"datatype": "string",
"transform": null
},
{
"column": "specversion",
"path": "$.specversion",
"datatype": "string",
"transform": null
},
{
"column": "type",
"path": "$.type",
"datatype": "string",
"transform": null
},
{
"column": "datacontenttype",
"path": "$.datacontenttype",
"datatype": "string",
"transform": null
},
{
"column": "dataschema",
"path": "$.dataschema",
"datatype": "string",
"transform": null
},
{
"column": "subject",
"path": "$.subject",
"datatype": "string",
"transform": null
},
{
"column": "time",
"path": "$.time",
"datatype": "datetime",
"transform": null
},
{
"column": "data",
"path": "$.data",
"datatype": "dynamic",
"transform": null
}
]
```
// Ingestion mapping for flight events
.create-or-alter table typeb_flight_events ingestion json mapping "typeb_flight_events_mapping"
```
[
{
"column": "id",
"path": "$.id",
"datatype": "string",
"transform": null
},
{
"column": "source",
"path": "$.source",
"datatype": "string",
"transform": null
},
{
"column": "specversion",
"path": "$.specversion",
"datatype": "string",
"transform": null
},
{
"column": "type",
"path": "$.type",
"datatype": "string",
"transform": null
},
{
"column": "datacontenttype",
"path": "$.datacontenttype",
"datatype": "string",
"transform": null
},
{
"column": "dataschema",
"path": "$.dataschema",
"datatype": "string",
"transform": null
},
{
"column": "subject",
"path": "$.subject",
"datatype": "string",
"transform": null
},
{
"column": "time",
"path": "$.time",
"datatype": "datetime",
"transform": null
},
{
"column": "data",
"path": "$.data",
"datatype": "dynamic",
"transform": null
}
]
```

Silver Layer via Update Policy

Rather than running a scheduled job to promote Bronze to Silver, Update Policies do this automatically at ingest time. Define a function that transforms the raw event, then attach it as a policy. In the following example I’ve embedded my KQL query directly in the policy. You could instead create a KQL function for this query and then reference it here instead.

.alter table ['Airport.Passenger.Checkin_v1'] policy update
```
[
{
"IsEnabled": true,
"Source": "airport_events",
"Query": "let bags = airport_events
| where type == 'Airport.Passenger.Checkin' and isnull(array_length(data))==true;
let arrays = airport_events
| where type == 'Airport.Passenger.Checkin' and isnull(array_length(data))==false
| mv-expand data;
bags
| union arrays
| project
___id = tostring(id),
___source = tostring(source),
___type = tostring(type),
___time = todatetime(['time']),
___subject = tostring(subject),
flightId = tostring(data.flightId),
flightNumber = tostring(data.flightNumber),
airline = tostring(data.airline),
origin = tostring(data.origin),
destination = tostring(data.destination),
departureUtc = tostring(data.departureUtc),
paxId = tostring(data.paxId),
name = tostring(data.name)",
"IsTransactional": false,
"PropagateIngestionProperties": false
}
]
```
// Legacy table name aliases (functions for backward compatibility)
.create-or-alter function airport_passenger_checkin() {
['Airport.Passenger.Checkin_v1']
}

Every event that lands in BaggageEvents_Bronze is automatically transformed and inserted into BaggageEvents_Silver — no pipelines, no orchestration.

Gold Layer via Materialized Views

Materialized Views pre-aggregate data so your dashboard queries are fast, even against billions of rows. Here is a sample useful ones for this use case:

// Gold: latest status per flight
.create materialized-view flights_current on table flights {
flights
| summarize arg_max(updated, *) by flightId
}

When we’re done, we should see our database schema of tables, materialized views, and functions:

Step 3: Configure the Eventstream

Now wire up the ingestion pipeline. In your Fabric workspace, click New → Eventstream and name it evs-airport-events.

Option A: Azure Event Hubs as Source (what I’m doing)

If you’re publishing events from the Baggage Handling Simulator to Azure Event Hubs:

  1. In the Eventstream canvas, click Add source → Azure Event Hubs
  2. Enter your Event Hubs namespace, hub name, and connection string (or use a Fabric connection)
  3. Set the consumer group — use $Default for dev/test
  4. Set the data format — use json

Option B: Custom Endpoint (no Event Hubs needed)

Fabric Eventstream also exposes a custom endpoint — an HTTPS or AMQP ingest URL you can publish CloudEvents directly to, without needing an external Event Hubs namespace. This is great for demos and local testing.

  1. Click Add source → Custom endpoint
  2. Copy the connection string — you’ll use this in the simulator config

Add the Eventhouse Destination

  1. Click Add destination → Eventhouse
  2. Select the Airport-Eventhouse Eventhouse and the KQL database
  3. Select the airport_events table and the airport_events_mapping ingestion mapping

Once everything is setup, this is what we should see:

One of the nice features in Fabric Eventhouse that we don’t see in Azure Data Explorer is the Entity Diagram, which is currently in preview. Go back to your KQL database main view and click on the entity diagram button:

Step 4: Run the Baggage Handling Simulator

Clone the simulator and install dependencies:

git clone https://github.com/calloncampbell/BaggageHandling-TypeB-Simulator.git
cd BaggageHandlingSimulator
pip install -r requirements.txt

Configure the connection string for your Event Hubs namespace or Fabric custom endpoint in config.json (or as environment variables — check the repo README for the exact format).

Run the simulator:

python -m baggage_simulator.cli --verbose --clock-speed 120 --flight-interval-minutes 5 --max-active-flights 5 --eventhub-conn "**********************" --eventhub-name "airport-events-evh"

The --speed multiplier lets you fast-forward simulation time so you don’t have to wait hours for bags to travel through their lifecycle. With --clock-speed 120, a full flight’s baggage cycle completes in minutes.

Within seconds, you should see events flowing into the Eventstream and landing in the Eventhouse Bronze tables.

Step 5: Query the Data

Open a KQL Queryset in your workspace and start exploring. Here are a few queries I find useful:

Track a specific bag end-to-end

BaggageEvents_Silver
| where BagTagNumber == "0014567891234"
| order by Timestamp asc
| project Timestamp, EventCategory, Location, FlightNumber

Find bags that haven’t been delivered (potential mishandles)

BagLatestStatus
| where EventCategory != "Delivered" and EventCategory != "Lost"
| where Timestamp < ago(2h)
| project BagTagNumber, FlightNumber, EventCategory, Location, Timestamp
| order by Timestamp asc

Baggage throughput by event type over the last hour

BaggageEventsByHour
| where Timestamp > ago(1h)
| summarize Total = sum(EventCount) by EventType
| order by Total desc
| render barchart

Average bag journey time (check-in to delivery) per flight

let CheckIn = BaggageEvents_Silver | where EventCategory == "CheckedIn" | project BagTagNumber, CheckInTime = Timestamp;
let Delivered = BaggageEvents_Silver | where EventCategory == "Delivered" | project BagTagNumber, DeliveredTime = Timestamp;
CheckIn
| join kind=inner Delivered on BagTagNumber
| extend JourneyMinutes = datetime_diff('minute', DeliveredTime, CheckInTime)
| summarize AvgJourneyMinutes = avg(JourneyMinutes), BagCount = count() by bin(CheckInTime, 1h)
| order by CheckInTime desc

Step 6: Build the Real-Time Dashboard

Create a Real-Time Dashboard in your workspace. Add tiles by writing KQL queries directly in the dashboard editor — no separate report tool needed.

You can always view the query for each of the tiles by clicking on the … menu and then view query:

Useful tiles for this scenario:

  • Bags in-flight right now — count of bags with a status other than Delivered or Lost
  • Events per minute — a time chart showing ingestion rate
  • Lost or rejected bags — a table filtered to EventCategory in ("Lost", "Rejected")
  • Baggage throughput by hour — bar or area chart of event volume over time

Set the dashboard auto-refresh to 30 seconds for a live operations feel.

Step 7: Set Up an Activator Alert

Activator is Fabric’s alerting engine, and this is where things get genuinely useful. You can define a rule that watches a KQL query result and triggers an action when a condition is met.

From the Real-Time Dashboard, click Set alert on the “Lost or rejected bags” tile. Configure:

  • Condition: row count > 0
  • Action: send an email, Teams message, or trigger a Power Automate flow
  • Check frequency: every 5 minutes

You can also create Activator items directly from the Eventhouse using Data Activator and write your own detection query — useful for more complex conditions like “bag hasn’t progressed in 45 minutes”:

BagLatestStatus
| where EventCategory !in ("Delivered", "Lost")
| where Timestamp < ago(45m)

Putting It All Together

Here’s the full flow end-to-end:

  1. Simulator generates CloudEvents and publishes to Event Hubs / Eventstream endpoint
  2. Eventstream ingests, routes by event type, and writes to Bronze tables in Eventhouse
  3. Update Policies automatically promote Bronze → Silver on ingest
  4. Materialized Views continuously aggregate Silver → Gold
  5. KQL Querysets power ad-hoc investigation
  6. Real-Time Dashboard shows live operations at a glance
  7. Activator fires alerts when something goes wrong

The whole pipeline is serverless from the Eventstream inward — there’s no infrastructure to manage, no Spark jobs to schedule, and no orchestration to babysit.

That’s what I find most impressive about Fabric RTI for this kind of scenario. The time from “event published” to “insight on a dashboard with an alert configured” is measured in minutes, not weeks.

Enjoy!

References

AviationGames

C-46 Comes to Microsoft Flight

c-46The C-46 has arrived! I know I know I know, how is it possible that new content has appeared for Microsoft Flight after development was discontinued? Well it seems as though this aircraft was complete, but they still needed to do the paperwork to get it released.

You can read more about the release of the C-46 on Microsoft Flight here and here.

This plane was originally built as a cargo and troop transport during WWII. This twin engine aircraft can carry up to 17,000 lbs of fuel and cargo to almost any remote and rugged landing strip. It has a relatively high cruising speed of 200 kts and a maximum range of 1500 miles. This makes it the perfect cargo aircraft for Alaska.

Features

  • Authentic Model: Beautifully rendered exterior of the C-46 and its Pratt and Whitney R-2800 engines give you a realistic experience.
  • Great Cargo-Carrying Capability: Over 17,000 pounds of fuel and cargo capacity allows flexibility and efficiency in completing jobs.
  • No cockpit view is included.

Final Thoughts

I think this is a great addition to Microsoft Flight and is an aircraft I look forward to flying. It’s too bad that there is no cockpit view.

I know I’ve mentioned this in the past, but I really wish there was a way for the community and 3rd party vendors to create additional content (aircraft, maps, etc) for Microsoft Flight.

Happy Flying!

References

AviationGames

Microsoft Flight–Development Grounded

microsoftflightSadly on July 25, 2012 Microsoft announced it has cancelled further development of Microsoft Flight and the team has been scrapped and any plans for future content have been scuttled.

That’s too bad because I was really enjoying Flight and just started to fly in the new Alaskan Wilderness pack.

Microsoft has commented that they will continue to support the community that has embraced Microsoft Flight and that it will continue to be offered as a free download. You will also be able to buy any of the DLC material.

I’ve bought all my DLC material from Steam as they have sales and bundles. If you like Microsoft Flight and are thinking about buying any DLC…watch for sales on Steam. I suspect with development grounded, the prices won’t remain as high as they are now.

The community complained that the flight simulation lacked extensive terrain, aircraft and support for 3rd party content. Perhaps Microsoft should open up Flight and let the community extend it.

Anyway for the time being, I will continue to enjoy what Microsoft Flight brings until such a time a new simulator emerges from Microsoft. Maybe we will see a flight simulator tailored to Windows 8.

AviationGames

Steam Summer Sale (Including Microsoft Flight)

The Steam Summer Sale has started, and all Microsoft Flight DLC is 40% off until July 23rd.

Check out the sale here: http://store.steampowered.com/dlc/203850/

I just purchased the Microsoft Flight: Alaskan Wilderness pack. I’m very excited to give this a try.

Alaskan Wilderness

AviationGames

Flying in Alaska

Microsoft will soon release its second expansion, Alaska Wilderness DLC for Microsoft Flight.

Like Hawaii, with its rich history of military aviation, Alaska has also seen its share of airborne hostilities. The difference is that the opponents in Alaska aren’t other pilots: they’re the elements and terrain itself. In a land where the nearest roads might be hundreds of miles away, planes provide the only efficient way to travel and transport cargo over long distances. You’ll face capricious crosswinds over mysterious vistas, unpredictable terrain with isolated and difficult landing strips, and other challenges in this land of fierce and dangerous beauty. Are you ready to take on the Alaskan Wilderness?

Look for this adventure to be available soon. Until then here are some awesome screenshots:

252358_367885296606791_100257846702872_964339_1414536857_n

Alaska Teaser 4

Alaska Teaser 3

AviationTechnology

Infinite Flight (mobile flight sim)

logo

Last year when I got my first Windows Phone, the Samsung Focus…I was browsing the Marketplace and came across a Flight Simulator called Infinite Flight. I downloaded and tried the demo out at the time, and loved what I saw.

Almost a year later…I upgraded to a Nokia Lumia 900 and decided to pull the trigger and finally get this awesome simulator.

Here is a quick description of Infinite Flight and some of the features. If you’re an avid flight simulator, have a passion for aviation and own either an iPhone or Windows Phone…then I highly recommend you try it out.

Plus I read that they’re looking to support Windows 8 and Windows Phone 8!

http://flyingdevstudio.blogspot.co.uk/

Infinite Flight

Infinite Flight is the first Flight Simulator for iOS and Windows Phone 7 developed by a team of 2 highly dedicated developers.

 

Features

  • Great airplanes selection (varies with the platform): C-17 Globemaster III, Supermarine Spitfire, Airbus A380-800, Boeing 747-400, A-10, Boeing 737-800, Cessna 172SP, Cirrus SR22, Super Decathlon, F/A-18 Hornet, Airbus A321, Boeing 787-900 Dreamliner, A-10 warthog
  • 2 Regions: San Francisco Bay Area and Southern California
  • Flight Planning
  • Realistic Flight Model
  • Interactive Flight Lessons
  • Autopilot (Altitude and Heading, Throttle)
  • 4 time presets (Sunrise, Day, Sunset and Night)
  • Weather settings: Wind direction and intensity, visibility…
  • Yoke helper for easy handling of the airplane
  • Final Approach Path Display to help with landings
  • ILS (Instrument Landing System)
  • Realistic sounds
  • 5 Camera Modes
  • Runway lights
  • Automatic Logbook (entries added for each flight)
  • Leaderboards
  • Achievements

Screenshots

fullsize_5

747

fullsize_6

fullsize_7

AviationGames

Microsoft Flight is now free to play on Steam

Microsoft Flightis Now Available and Free to Play on Steam.

Experience the thrill and wonder of flight with Microsoft Flight. This free download gives you the opportunity to explore the skies over the beautiful Big Island of Hawaii in the state-of-the-art Icon A5 or the classic Boeing Stearman. Enjoy hours of gameplay with a variety of exciting missions, challenges that will test your skills, and hidden Aerocaches that will give you yet another reason to explore.

capsule_467x181

The Steam edition is different to the original Microsoft Flight version in that it provides better pricing via the Hawaiian Starter Bundle, which is cheaper on Steam by $13 than it is on the Xbox.com Marketplace. The bundle includes two aircraft, the Maule M-7-260C and the North American P-51 Mustang, and the Hawaiian Adventure itself.

I’ve switched to using Steam when playing and buying any game content for Microsoft Flight. I like the pricing model and the game is always kept up to date.

If you haven’t tried Microsoft Flight yet, you should.

AviationGames

Microsoft Flight

Microsoft released Microsoft Flight on February 29, 2012 as a free game, with additional purchasable downloadable content for items such as additional planes and locations.

The sky’s the limit! Experience the thrill and wonder of flight with Microsoft Flight. Now anyone can enjoy the fun, freedom and adventure of flight. Feel the power at your fingertips as you take to the skies and launch into thrilling missions and exciting challenges over the free-to-play Big Island of Hawaii. Take off today and fly into the ever-expanding world of Microsoft Flight.

This free download gives you the opportunity to explore the skies over the beautiful Big Island of Hawaii in the state-of-the-art Icon A5 or the classic Boeing Stearman.

MSFlight

SYSTEM REQUIREMENTS:

  • Direct X Version: DirectX 9.0c Shader Model 3.0
  • Memory: 2.0 GB
  • Operating System: Windows® XP with Service Pack 3
  • Processor: Dual Core 2.0 GHz or higher
  • Graphics: 256 MB (DirectX 9.0c Shader Model 3.0 compatible)
  • Hard Disk Space: 773 MB

START FLYING NOW… IT ONLY TAKES A FEW MINUTES TO GET IN THE AIR!
GAMERTAG NOT REQUIRED TO DOWNLOAD AND PLAY THE FREE VERSION.

The free version includes everything you need to take-off and fly around the Big Island of Hawaii including the following:

  • Tutorials
  • Play Online or Offline
  • Includes the Icon A5
  • Missions
  • Hidden Aerocaches

Flight is available at the Xbox Marketplace.