diff --git a/src/agent.c b/src/agent.c
index bb29a3f4df426e78c69406b37f8d7ce8b87f20e1..0f66775ef54c63bd738381356eb7dc7464006c47 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -1749,18 +1749,6 @@ static void wifi_sta_periodic_run(atimer_t *t)
 		return;
 	}
 
-	if (s->rssi_avg[0] && s->rssi_avg[1]) {
-		struct agent_config_radio *rcfg =
-			get_agent_config_radio(&a->cfg, ap->cfg->device);
-		uint8_t curr_rcpi = rssi_to_rcpi(s->rssi_avg[0]);
-		uint8_t prev_rcpi = rssi_to_rcpi(s->rssi_avg[1]);
-		uint8_t trigger = rcfg->report_rcpi_threshold;
-
-		if ((prev_rcpi <= trigger && curr_rcpi > trigger) ||
-		    (prev_rcpi >= trigger && curr_rcpi < trigger))
-			timer_set(&a->rcpi_threshold_timer, 0);
-	}
-
 	if (sta_steer_allowed(s->steer_policy)
 			&& !list_empty(&s->pref_nbrlist)
 			&& maybe_steer_sta(s, &reason, &pref_nbr)) {
@@ -1771,6 +1759,42 @@ static void wifi_sta_periodic_run(atimer_t *t)
 	if (!list_empty(&ap->nbrlist) && list_empty(&s->pref_nbrlist))
 		recalc_desired_neighbors(s);
 
+	if (s->rssi_avg[0] && s->rssi_avg[1]) {
+		struct agent_config_radio *rcfg;
+		uint8_t trig_l, trig_h;
+		uint8_t curr_rcpi, prev_rcpi;
+
+		rcfg = get_agent_config_radio(&a->cfg, ap->cfg->device);
+		if (!rcfg)
+			goto rearm_periodic;
+
+		if (!rcfg->report_rcpi_threshold)
+			goto rearm_periodic;
+
+		trig_l = rcfg->report_rcpi_threshold - rcfg->rcpi_hysteresis_margin;
+		trig_h = rcfg->report_rcpi_threshold + rcfg->rcpi_hysteresis_margin;
+		curr_rcpi = rssi_to_rcpi(s->rssi_avg[0]);
+		prev_rcpi = rssi_to_rcpi(s->rssi_avg[1]);
+
+		if (curr_rcpi > trig_l && curr_rcpi < trig_h) {
+			/* rcpi in range, stop sample collection */
+			s->num_rssi_rep = 0;
+		} else if ((prev_rcpi < trig_h && curr_rcpi >= trig_h) ||
+		    (prev_rcpi > trig_l && curr_rcpi <= trig_l)) {
+			/* passed report trigger, (re)start sample collection */
+			s->num_rssi_rep = 1;
+		} else {
+			/* rcpi outside range for consecutive sample */
+			if (s->num_rssi_rep == MAX_RSSI_MEAS) {
+				/* interpret collected samples */
+				timer_set(&a->rcpi_threshold_timer, 0);
+			} else {
+				/* collect next sample */
+				s->num_rssi_rep++;
+			}
+		}
+	}
+
 rearm_periodic:
 	timer_set(&s->sta_timer, STA_PERIODIC_RUN_INTERVAL);
 }
@@ -3750,59 +3774,62 @@ static void agent_rcpi_thresold_timer_cb(atimer_t *t)
 				continue;
 
 			list_for_each_entry(s, &ap->stalist, list) {
-				uint8_t report_rcpi = rcfg->report_rcpi_threshold;
-				uint8_t curr_rcpi, prev_rcpi;
+				struct cmdu_buff *cmdu;
+				char ev_data[512] = {0};
+				uint8_t rcpi_low, rcpi_high; /* RCPI triggers */
+				int i, num_rssi_low = 0, num_rssi_high = 0;
 
 				dbg("%s %d found client "MACFMT"\n", __func__, __LINE__, MAC2STR(s->macaddr));
 
-				/* Note: Using average RSSI for all triggers */
-				curr_rcpi = rssi_to_rcpi(s->rssi_avg[0]);
-				prev_rcpi = rssi_to_rcpi(s->rssi_avg[1]);
-
-				if ((curr_rcpi < report_rcpi) ||
-				    (curr_rcpi > report_rcpi && prev_rcpi <= report_rcpi)) {
-					struct cmdu_buff *cmdu;
-					char ev_data[512] = {0};
-
-					snprintf(ev_data, sizeof(ev_data),
-						"{\"macaddr\":\""MACFMT"\""
-						",\"report_rcpi_threshold\":%d"
-						",\"rcpi\":%d}",
-						MAC2STR(s->macaddr),
-						rcfg->report_rcpi_threshold, curr_rcpi);
-
-					if (curr_rcpi < report_rcpi)
-						agent_notify_iface_event(a, ap->ifname,
-								"sta_low_rcpi", ev_data);
-					else
-						agent_notify_iface_event(a, ap->ifname,
-								"sta_high_rcpi", ev_data);
-
-					cmdu = agent_gen_assoc_sta_metric_responsex(a,
-						a->cntlr_almac, s, ap);
-					if (cmdu) {
-						agent_send_cmdu(a, cmdu);
-						cmdu_free(cmdu);
-					}
+				if (s->num_rssi_rep < MAX_RSSI_MEAS) {
+					dbg("%s: incomplete number of samples (%d) for report, continue\n",
+					    __func__, s->num_rssi_rep);
+					continue;
 				}
 
-			}
+				rcpi_low = rcfg->report_rcpi_threshold - rcfg->rcpi_hysteresis_margin;
+				rcpi_high = rcfg->report_rcpi_threshold + rcfg->rcpi_hysteresis_margin;
+
+				/* Using average RSSI for all triggers */
+				for (i = 0; i < s->num_rssi_rep; i++) {
+					if (rssi_to_rcpi(s->rssi_avg[i]) <= rcpi_low)
+						num_rssi_low++;
+					else if (rssi_to_rcpi(s->rssi_avg[i]) >= rcpi_high)
+						num_rssi_high++;
+				}
+
+				if (num_rssi_low && num_rssi_high) {
+					/* should not happen */
+					err("%s: mixed samples below & above RCPI triggers!\n", __func__);
+					continue;
+				}
 
+				snprintf(ev_data, sizeof(ev_data),
+					"{\"macaddr\":\""MACFMT"\""
+					",\"report_rcpi_threshold\":%d"
+					",\"rcpi_hysteresis_margin\":%d"
+					",\"rcpi\":%d}",
+					MAC2STR(s->macaddr),
+					rcfg->report_rcpi_threshold,
+					rcfg->rcpi_hysteresis_margin,
+					rssi_to_rcpi(s->rssi_avg[0]));
+
+				if (num_rssi_low)
+					agent_notify_iface_event(a, ap->ifname, "sta_low_rcpi", ev_data);
+				else
+					agent_notify_iface_event(a, ap->ifname, "sta_high_rcpi", ev_data);
+
+				/* send the report */
+				cmdu = agent_gen_assoc_sta_metric_responsex(a, a->cntlr_almac, s, ap);
+				if (cmdu) {
+					agent_send_cmdu(a, cmdu);
+					cmdu_free(cmdu);
+				}
+			}
 		}
-	}
 
-/*	curr_rcpi = calculate_radio_rcpi(a, p->ifname);
-	prev_rcpi = p->prev_rcpi;
-	if (((prev_rcpi > p->cfg->rcpi_threshold) &&
-				(curr_rcpi > p->cfg->rcpi_threshold)) ||
-			((prev_rcpi < p->cfg->rcpi_threshold) &&
-			 (curr_rcpi < p->cfg->rcpi_threshold)))
-		goto refresh_interval;
-*/
-	//prepare_assoc_sta_metric_response(a, p->ifname);
+	}
 
-//refresh_interval:
-//	p->prev_rcpi = curr_rcpi;
 	timer_set(&a->rcpi_threshold_timer, RCPI_THRESHOLD_TIMER);
 }
 
diff --git a/src/agent.h b/src/agent.h
index 863f5ad3cd78ddadaca2e6a31a41c632c80d3435..a68cf6797378e0fb060cd6af49edbc524430da96 100644
--- a/src/agent.h
+++ b/src/agent.h
@@ -459,9 +459,10 @@ struct sta {
 #endif
 	uint32_t caps;                  /** capability bitmap */
 	int rssi[WIFI_NUM_ANTENNA];     /** rssi of last received pkt */
-#define MAX_RSSI_MEAS 2
+#define MAX_RSSI_MEAS 3
 	int8_t rssi_avg[MAX_RSSI_MEAS]; /** average rssi history FIFO buffer */
-	uint8_t num_rssi;               /** number of RSSI samples */
+	uint8_t num_rssi;               /** total number of RSSI samples aggregated */
+	uint8_t num_rssi_rep;           /** number of RSSI samples collected for report */
 	uint64_t connected_ms;          /** number of msecs connected */
 	struct timespec last_update;
 	uint32_t tx_rate;
diff --git a/src/config.c b/src/config.c
index 1e531bdb287f5219afd970586588c3971ecd3844..b3c024261752ee2131f08d13d721069239dbace0 100644
--- a/src/config.c
+++ b/src/config.c
@@ -2572,7 +2572,8 @@ static int agent_config_get_wifi_radio(struct agent_config *a,
 	}
 
 	if (ifname && band) {
-		uint8_t rcpi_threshold = 0, report_rcpi_threshold = 0;
+		uint8_t rcpi_threshold = 0;
+		uint8_t report_rcpi_threshold = 0;
 
 		n = get_agent_config_radio(a, ifname);
 		if (!n) {
@@ -2661,6 +2662,8 @@ static int agent_config_get_wifi_radio(struct agent_config *a,
 		if (tb[WIFI_RADIO_RCPI_HYSTERESIS_MARGIN])
 			n->rcpi_hysteresis_margin =
 				atoi(tb[WIFI_RADIO_RCPI_HYSTERESIS_MARGIN]->v.string);
+		else
+			n->rcpi_hysteresis_margin = 0;
 
 		if (tb[WIFI_RADIO_REPORT_UTIL_THRESHOLD])
 			n->report_util_threshold =