private synchronized void publishNow() {
    if (!isRunning()) return;

    CalculatedStatus calculatedStatus = calculateStatus();
    boolean connected = calculatedStatus.connected;

    Long lastUpTime = connectionLastUp.get();
    Long lastDownTime = connectionLastDown.get();
    long serviceFailedStabilizationDelay = getConnectionFailedStabilizationDelay().toMilliseconds();
    long serviceRecoveredStabilizationDelay =
        getConnectionRecoveredStabilizationDelay().toMilliseconds();
    long now = System.currentTimeMillis();

    if (connected) {
      if (lastPublished == LastPublished.FAILED) {
        // only publish if consistently up for serviceRecoveredStabilizationDelay
        long currentRecoveryPeriod = getTimeDiff(now, currentRecoveryStartTime);
        long sinceLastDownPeriod = getTimeDiff(now, lastDownTime);
        if (currentRecoveryPeriod > serviceRecoveredStabilizationDelay
            && sinceLastDownPeriod > serviceRecoveredStabilizationDelay) {
          String description = calculatedStatus.getDescription();
          LOG.warn(
              "{} connectivity-check for {}, publishing recovered: {}",
              new Object[] {this, entity, description});
          entity.emit(CONNECTION_RECOVERED, new HASensors.FailureDescriptor(entity, description));
          lastPublished = LastPublished.RECOVERED;
          currentFailureStartTime = null;
        } else {
          long nextAttemptTime =
              Math.max(
                  serviceRecoveredStabilizationDelay - currentRecoveryPeriod,
                  serviceRecoveredStabilizationDelay - sinceLastDownPeriod);
          schedulePublish(nextAttemptTime);
        }
      }
    } else {
      if (lastPublished != LastPublished.FAILED) {
        // only publish if consistently down for serviceFailedStabilizationDelay
        long currentFailurePeriod = getTimeDiff(now, currentFailureStartTime);
        long sinceLastUpPeriod = getTimeDiff(now, lastUpTime);
        if (currentFailurePeriod > serviceFailedStabilizationDelay
            && sinceLastUpPeriod > serviceFailedStabilizationDelay) {
          String description = calculatedStatus.getDescription();
          LOG.warn(
              "{} connectivity-check for {}, publishing failed: {}",
              new Object[] {this, entity, description});
          entity.emit(CONNECTION_FAILED, new HASensors.FailureDescriptor(entity, description));
          lastPublished = LastPublished.FAILED;
          currentRecoveryStartTime = null;
        } else {
          long nextAttemptTime =
              Math.max(
                  serviceFailedStabilizationDelay - currentFailurePeriod,
                  serviceFailedStabilizationDelay - sinceLastUpPeriod);
          schedulePublish(nextAttemptTime);
        }
      }
    }
  }
  private synchronized void checkHealth() {
    CalculatedStatus status = calculateStatus();
    boolean connected = status.connected;
    long now = System.currentTimeMillis();

    if (connected) {
      connectionLastUp.set(now);
      if (lastPublished == LastPublished.FAILED) {
        if (currentRecoveryStartTime == null) {
          LOG.info(
              "{} connectivity-check for {}, now recovering: {}",
              new Object[] {this, entity, status.getDescription()});
          currentRecoveryStartTime = now;
          schedulePublish();
        } else {
          if (LOG.isTraceEnabled())
            LOG.trace(
                "{} connectivity-check for {}, continuing recovering: {}",
                new Object[] {this, entity, status.getDescription()});
        }
      } else {
        if (currentFailureStartTime != null) {
          LOG.info(
              "{} connectivity-check for {}, now healthy: {}",
              new Object[] {this, entity, status.getDescription()});
          currentFailureStartTime = null;
        } else {
          if (LOG.isTraceEnabled())
            LOG.trace(
                "{} connectivity-check for {}, still healthy: {}",
                new Object[] {this, entity, status.getDescription()});
        }
      }
    } else {
      connectionLastDown.set(now);
      if (lastPublished != LastPublished.FAILED) {
        if (currentFailureStartTime == null) {
          LOG.info(
              "{} connectivity-check for {}, now failing: {}",
              new Object[] {this, entity, status.getDescription()});
          currentFailureStartTime = now;
          schedulePublish();
        } else {
          if (LOG.isTraceEnabled())
            LOG.trace(
                "{} connectivity-check for {}, continuing failing: {}",
                new Object[] {this, entity, status.getDescription()});
        }
      } else {
        if (currentRecoveryStartTime != null) {
          LOG.info(
              "{} connectivity-check for {}, now failing: {}",
              new Object[] {this, entity, status.getDescription()});
          currentRecoveryStartTime = null;
        } else {
          if (LOG.isTraceEnabled())
            LOG.trace(
                "{} connectivity-check for {}, still failed: {}",
                new Object[] {this, entity, status.getDescription()});
        }
      }
    }
  }