Show code
viewof pfNumericFields = Inputs.range([0, 20], {
value: 3,
step: 1,
label: "Number of numeric fields (int/float):"
})
viewof pfStringFields = Inputs.range([0, 10], {
value: 2,
step: 1,
label: "Number of string fields:"
})
viewof pfAvgKeyLen = Inputs.range([3, 20], {
value: 8,
step: 1,
label: "Average key name length (chars):"
})
viewof pfAvgStringLen = Inputs.range([3, 50], {
value: 10,
step: 1,
label: "Average string value length (chars):"
})
viewof pfMsgsPerDay = Inputs.range([1, 100000], {
value: 1440,
step: 100,
label: "Messages per device per day:"
})
// JSON: keys quoted + colons + commas + braces + values
pfJsonKeyOverhead = (pfNumericFields + pfStringFields) * (pfAvgKeyLen + 3) // quotes around key + colon
pfJsonNumValues = pfNumericFields * 6 // avg numeric representation ~6 chars
pfJsonStrValues = pfStringFields * (pfAvgStringLen + 2) // quotes around strings
pfJsonStructure = 2 + Math.max(0, pfNumericFields + pfStringFields - 1) // braces + commas
pfJsonSize = pfJsonKeyOverhead + pfJsonNumValues + pfJsonStrValues + pfJsonStructure
// CBOR: binary encoding, ~1 byte per key header, compact values
pfCborKeyOverhead = (pfNumericFields + pfStringFields) * (1 + pfAvgKeyLen) // 1 byte type header + key bytes
pfCborNumValues = pfNumericFields * 5 // varint encoding, typically 3-5 bytes
pfCborStrValues = pfStringFields * (1 + pfAvgStringLen) // 1 byte header + string
pfCborStructure = 1 // map header
pfCborSize = pfCborKeyOverhead + pfCborNumValues + pfCborStrValues + pfCborStructure
// Protobuf: field tags + wire types, no key names
pfProtobufNumValues = pfNumericFields * 6 // tag (1-2) + varint (1-4)
pfProtobufStrValues = pfStringFields * (2 + pfAvgStringLen) // tag + length prefix + value
pfProtobufSize = pfProtobufNumValues + pfProtobufStrValues
// MessagePack: similar to CBOR but slightly larger
pfMsgpackSize = Math.round(pfCborSize * 1.08)
pfJsonDaily = pfJsonSize * pfMsgsPerDay
pfCborDaily = pfCborSize * pfMsgsPerDay
pfProtobufDaily = pfProtobufSize * pfMsgsPerDay
pfCborSavings = ((pfJsonSize - pfCborSize) / pfJsonSize * 100)
pfProtobufSavings = ((pfJsonSize - pfProtobufSize) / pfJsonSize * 100)
html`<div style="background: #f8f9fa; border-left: 4px solid #2C3E50; padding: 15px; margin-top: 15px; font-family: Arial, sans-serif;">
<h4 style="color: #2C3E50; margin-top: 0;">Estimated Payload Sizes by Format</h4>
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 10px; margin-top: 10px;">
<div style="background: white; padding: 12px; border-radius: 4px; border: 1px solid #e0e0e0;">
<div style="color: #7F8C8D; font-size: 11px; text-transform: uppercase; margin-bottom: 4px;">JSON</div>
<div style="color: #3498DB; font-size: 22px; font-weight: bold;">${pfJsonSize} B</div>
<div style="color: #7F8C8D; font-size: 11px;">Baseline (human-readable)</div>
</div>
<div style="background: white; padding: 12px; border-radius: 4px; border: 1px solid #e0e0e0;">
<div style="color: #7F8C8D; font-size: 11px; text-transform: uppercase; margin-bottom: 4px;">CBOR</div>
<div style="color: #16A085; font-size: 22px; font-weight: bold;">${pfCborSize} B</div>
<div style="color: #16A085; font-size: 11px;">${pfCborSavings.toFixed(0)}% smaller than JSON</div>
</div>
<div style="background: white; padding: 12px; border-radius: 4px; border: 1px solid #e0e0e0;">
<div style="color: #7F8C8D; font-size: 11px; text-transform: uppercase; margin-bottom: 4px;">Protocol Buffers</div>
<div style="color: #E67E22; font-size: 22px; font-weight: bold;">${pfProtobufSize} B</div>
<div style="color: #E67E22; font-size: 11px;">${pfProtobufSavings.toFixed(0)}% smaller than JSON</div>
</div>
<div style="background: white; padding: 12px; border-radius: 4px; border: 1px solid #e0e0e0;">
<div style="color: #7F8C8D; font-size: 11px; text-transform: uppercase; margin-bottom: 4px;">MessagePack</div>
<div style="color: #9B59B6; font-size: 22px; font-weight: bold;">${pfMsgpackSize} B</div>
<div style="color: #9B59B6; font-size: 11px;">${((pfJsonSize - pfMsgpackSize) / pfJsonSize * 100).toFixed(0)}% smaller than JSON</div>
</div>
</div>
<div style="margin-top: 12px; display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
<div style="background: #f0f7ff; padding: 10px; border-radius: 4px; font-size: 13px; color: #2C3E50;">
<strong>Daily bandwidth per device:</strong><br/>
JSON: ${pfJsonDaily < 1024 ? pfJsonDaily + ' B' : pfJsonDaily < 1048576 ? (pfJsonDaily / 1024).toFixed(1) + ' KB' : (pfJsonDaily / 1048576).toFixed(2) + ' MB'} |
CBOR: ${pfCborDaily < 1024 ? pfCborDaily + ' B' : pfCborDaily < 1048576 ? (pfCborDaily / 1024).toFixed(1) + ' KB' : (pfCborDaily / 1048576).toFixed(2) + ' MB'}
</div>
<div style="background: #f0fff4; padding: 10px; border-radius: 4px; font-size: 13px; color: #2C3E50;">
<strong>Recommendation:</strong>
${pfJsonSize <= 50 ? 'Small payload -- JSON is fine for readability' : pfJsonSize <= 127 ? 'Medium payload -- consider CBOR for constrained links' : 'Large payload -- use CBOR or Protobuf to stay within LoRaWAN MTU limits'}
</div>
</div>
</div>`