   // FAILED if fallen through to here.
   return(false);
   }
-#endif
+#endif // ALLOW_CC1_SUPPORT_RELAY
+
+#ifdef ALLOW_CC1_SUPPORT_RELAY
+// True if a poll response is needed.
+// Cleared upon successful send.
+static bool pollResponseNeeded;
+// Send a CC1 poll response message with this unit's house code; returns false on failure.
+bool sendCC1PollResponse()
+  {
+  // Respond to the hub with sensor data.
+  // Can use read() for very freshest values at risk of some delay/cost.
+  const uint8_t hc1 = FHT8V.nvGetHC1();
+  const uint8_t hc2 = FHT8V.nvGetHC2();
+#ifdef HUMIDITY_SENSOR_SUPPORT
+  const uint8_t rh = RelHumidity.read() >> 1; // Scale from [0,100] to [0,50] for TX.
+#else
+  const uint8_t rh = 0; // RH% not available.
+#endif
+  const uint8_t tp = (uint8_t) constrain(extDS18B20_0.read() >> 3, 0, 199); // Scale to to 1/2C [0,100[ for TX.
+  const uint8_t tr = (uint8_t) constrain(TemperatureC16.read() >> 2, 0, 199); // Scale from 1/16C to 1/4C [0,50[ for TX.
+  const uint8_t al = AmbLight.read() >> 2; // Scale from [0,255] to [1,62] for TX (allow value coercion at extremes).
+  const bool s = getSwitchToggleStateCO();
+  const bool w = (fastDigitalRead(BUTTON_LEARN2_L) != LOW); // BUTTON_LEARN2_L high means open circuit means door/window open.
+  const bool sy = !NominalRadValve.isInNormalRunState(); // Assume only non-normal FHT8V state is 'syncing'.
+  OTProtocolCC::CC1PollResponse r =
+      OTProtocolCC::CC1PollResponse::make(hc1, hc2, rh, tp, tr, al, s, w, sy);
+  // Send message back to hub.
+  // Hub can poll again if it does not see the response.
+  // TODO: may need to insert a delay to allow hub to be ready if use of read() above is not enough.
+  uint8_t txbuf[OTProtocolCC::CC1PollResponse::primary_frame_bytes+1]; // More than large enough for preamble + sync + alert message.
+  const uint8_t bodylen = r.encodeSimple(txbuf, sizeof(txbuf), true);
+#if 1 && defined(DEBUG)
+  OTV0P2BASE::serialPrintlnAndFlush(F("polled"));
+#endif
+#if !defined(ENABLE_OTSECUREFRAME_ENCODING_SUPPORT)
+  // Non-secure: send raw frame as-is.
+  // Send at default power...  One going missing won't hurt that much.
+  if(!PrimaryRadio.sendRaw(txbuf, bodylen))
+    { OTV0P2BASE::serialPrintlnAndFlush(F("!TX fail")); return(false); } // FAIL
+#else
+  // Secure: wrap frame in encrypted layer...
+  uint8_t key[16];
+  if(!OTV0P2BASE::getPrimaryBuilding16ByteSecretKey(key))
+    { OTV0P2BASE::serialPrintlnAndFlush(F("!TX key")); return(false); } // FAIL
+  const OTRadioLink::SimpleSecureFrame32or0BodyTXBase::fixed32BTextSize12BNonce16BTagSimpleEnc_ptr_t e = OTAESGCM::fixed32BTextSize12BNonce16BTagSimpleEnc_DEFAULT_STATELESS;
+  uint8_t sbuf[OTRadioLink::SecurableFrameHeader::maxSmallFrameSize];
+  const uint8_t sbodylen = secureTXState.generateSecureOStyleFrameForTX(sbuf, sizeof(sbuf), OTRadioLink::FTS_RESERVED_A, lenTXID, txbuf, bodylen, e, NULL, key);
+  const bool success = (0 != sbodylen) && PrimaryRadio.sendRaw(sbuf+1, sbodylen-1);
+#if 1 && defined(DEBUG)
+  if(!success) { OTV0P2BASE::serialPrintlnAndFlush(F("!TX A")); }
+  else { OTV0P2BASE::serialPrintlnAndFlush(F("TX A")); }
+#endif
+  if(success)
+    {
+    // Note successful dispatch of response.
+    pollResponseNeeded = false;
+    return(true);
+    }
+#endif // !defined(ENABLE_OTSECUREFRAME_ENCODING_SUPPORT)
+  // FAILED if fallen through to here.
+  return(false);
+  }
+#endif // ALLOW_CC1_SUPPORT_RELAY
+
 
 #ifdef ALLOW_CC1_SUPPORT_RELAY_IO // REV9 CC1 relay...
 // Do basic static LED setting.

#endif // ALLOW_CC1_SUPPORT
#endif // ENABLE_FHT8VSIMPLE

  // Set appropriate loop() values just before entering it.
  TIME_LSD = OTV0P2BASE::getSecondsLT();
  }

  // no closer together than every about every 8 seconds,
  // randomly so as to minimise collisions with other regular traffic.
  if(waitingForPollAfterBoostRequest && (sec == (OTV0P2BASE::randRNG8() & 0x38)))
    { sendCC1Alert(); }

  return(false); // No human interaction this tick...
  }
