Update index.html
Browse files- index.html +108 -59
index.html
CHANGED
@@ -715,82 +715,83 @@
|
|
715 |
|
716 |
// Webhook Integration with improved reliability
|
717 |
const now = Date.now();
|
718 |
-
const criticalThreshold = 50;
|
719 |
-
const webhookCooldown = 30000;
|
720 |
|
721 |
if (temp > criticalThreshold && now - lastWebhookTimestamp > webhookCooldown) {
|
722 |
lastWebhookTimestamp = now;
|
723 |
logDebug(`Triggering webhook for critical temperature: ${temp}°C`);
|
724 |
|
725 |
-
// Generate
|
726 |
const csvData = generateCSV();
|
727 |
-
|
728 |
-
// Generate chart image
|
729 |
const chartImage = generateChartImage();
|
730 |
|
731 |
const sendWebhook = (attempt = 1) => {
|
732 |
const webhookUrl = 'https://n8n-1r4e.onrender.com/webhook-test/2af1157d-c7d7-4e57-86c8-577c5a005f40';
|
733 |
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
}
|
752 |
-
|
753 |
-
// Add chart image
|
754 |
-
if (chartImage) {
|
755 |
-
const chartBlob = dataURLtoBlob(chartImage);
|
756 |
-
formData.append('temperature_chart', chartBlob, 'temperature_chart.png');
|
757 |
-
}
|
758 |
-
|
759 |
-
logDebug(`Sending webhook attempt ${attempt} with attachments...`);
|
760 |
-
|
761 |
-
fetch(webhookUrl, {
|
762 |
-
method: 'POST',
|
763 |
-
headers: {
|
764 |
-
'X-ThermoScan-Signature': 'your-secret-key-here'
|
765 |
-
},
|
766 |
-
body: formData
|
767 |
-
})
|
768 |
-
.then(async res => {
|
769 |
-
if (!res.ok) {
|
770 |
-
const errorText = await res.text();
|
771 |
-
throw new Error(`HTTP ${res.status}: ${errorText}`);
|
772 |
}
|
773 |
-
|
774 |
-
|
775 |
-
|
776 |
-
|
777 |
-
|
778 |
-
|
779 |
-
|
780 |
-
logDebug(`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
781 |
if (attempt < 3) {
|
782 |
-
|
783 |
-
logDebug(`Retrying in ${retryDelay/1000} seconds...`);
|
784 |
-
setTimeout(() => sendWebhook(attempt + 1), retryDelay);
|
785 |
-
} else {
|
786 |
-
logDebug('Max retry attempts reached');
|
787 |
-
showAlert('Failed to send critical alert after 3 attempts', 'error');
|
788 |
}
|
789 |
-
}
|
790 |
};
|
791 |
|
792 |
sendWebhook();
|
793 |
-
}
|
|
|
794 |
const timeLeft = Math.ceil((webhookCooldown - (now - lastWebhookTimestamp)) / 1000);
|
795 |
logDebug(`Webhook cooldown active. ${timeLeft}s remaining until next alert can be sent`);
|
796 |
}
|
@@ -840,7 +841,55 @@
|
|
840 |
currentTempEl.classList.remove('text-warning-500', 'text-danger-500');
|
841 |
}
|
842 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
843 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
844 |
// Get status for history
|
845 |
function getStatus(temp) {
|
846 |
if (temp > 35) return 'critical';
|
|
|
715 |
|
716 |
// Webhook Integration with improved reliability
|
717 |
const now = Date.now();
|
718 |
+
const criticalThreshold = 50;
|
719 |
+
const webhookCooldown = 30000;
|
720 |
|
721 |
if (temp > criticalThreshold && now - lastWebhookTimestamp > webhookCooldown) {
|
722 |
lastWebhookTimestamp = now;
|
723 |
logDebug(`Triggering webhook for critical temperature: ${temp}°C`);
|
724 |
|
725 |
+
// Generate attachments
|
726 |
const csvData = generateCSV();
|
|
|
|
|
727 |
const chartImage = generateChartImage();
|
728 |
|
729 |
const sendWebhook = (attempt = 1) => {
|
730 |
const webhookUrl = 'https://n8n-1r4e.onrender.com/webhook-test/2af1157d-c7d7-4e57-86c8-577c5a005f40';
|
731 |
|
732 |
+
try {
|
733 |
+
const formData = new FormData();
|
734 |
+
|
735 |
+
// Add JSON payload
|
736 |
+
formData.append('payload', JSON.stringify({
|
737 |
+
temperature: temp,
|
738 |
+
timestamp: new Date().toISOString(),
|
739 |
+
status: getStatus(temp),
|
740 |
+
message: `⚠️ Critical temperature (${temp}°C) detected`,
|
741 |
+
deviceInfo: navigator.userAgent,
|
742 |
+
attempt: attempt
|
743 |
+
}));
|
744 |
+
|
745 |
+
// Add CSV file if available
|
746 |
+
if (csvData) {
|
747 |
+
const csvBlob = new Blob([csvData], { type: 'text/csv' });
|
748 |
+
formData.append('temperature_data', csvBlob, 'temperature_data.csv');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
749 |
}
|
750 |
+
|
751 |
+
// Add chart image if available
|
752 |
+
if (chartImage) {
|
753 |
+
const chartBlob = dataURLtoBlob(chartImage);
|
754 |
+
formData.append('temperature_chart', chartBlob, 'temperature_chart.png');
|
755 |
+
}
|
756 |
+
|
757 |
+
logDebug(`Sending webhook attempt ${attempt}...`);
|
758 |
+
|
759 |
+
fetch(webhookUrl, {
|
760 |
+
method: 'POST',
|
761 |
+
body: formData
|
762 |
+
})
|
763 |
+
.then(async res => {
|
764 |
+
if (!res.ok) {
|
765 |
+
const errorText = await res.text();
|
766 |
+
throw new Error(`HTTP ${res.status}: ${errorText}`);
|
767 |
+
}
|
768 |
+
return res.json();
|
769 |
+
})
|
770 |
+
.then(data => {
|
771 |
+
logDebug(`Webhook successful: ${JSON.stringify(data)}`);
|
772 |
+
showAlert('Critical alert sent successfully', 'success');
|
773 |
+
})
|
774 |
+
.catch(err => {
|
775 |
+
logDebug(`Webhook attempt ${attempt} failed: ${err.message}`);
|
776 |
+
if (attempt < 3) {
|
777 |
+
const retryDelay = 5000 * attempt;
|
778 |
+
logDebug(`Retrying in ${retryDelay/1000} seconds...`);
|
779 |
+
setTimeout(() => sendWebhook(attempt + 1), retryDelay);
|
780 |
+
} else {
|
781 |
+
showAlert('Failed to send critical alert', 'error');
|
782 |
+
}
|
783 |
+
});
|
784 |
+
} catch (error) {
|
785 |
+
logDebug(`Webhook preparation error: ${error.message}`);
|
786 |
if (attempt < 3) {
|
787 |
+
setTimeout(() => sendWebhook(attempt + 1), 5000 * attempt);
|
|
|
|
|
|
|
|
|
|
|
788 |
}
|
789 |
+
}
|
790 |
};
|
791 |
|
792 |
sendWebhook();
|
793 |
+
}
|
794 |
+
else if (temp > criticalThreshold) {
|
795 |
const timeLeft = Math.ceil((webhookCooldown - (now - lastWebhookTimestamp)) / 1000);
|
796 |
logDebug(`Webhook cooldown active. ${timeLeft}s remaining until next alert can be sent`);
|
797 |
}
|
|
|
841 |
currentTempEl.classList.remove('text-warning-500', 'text-danger-500');
|
842 |
}
|
843 |
}
|
844 |
+
// Generate CSV data from temperature history
|
845 |
+
function generateCSV() {
|
846 |
+
if (temperatureHistory.length === 0) return null;
|
847 |
+
|
848 |
+
let csvContent = "Timestamp,Temperature (°C),Status\n";
|
849 |
+
temperatureHistory.forEach(reading => {
|
850 |
+
csvContent += `${reading.timestamp},${reading.temp},${reading.status}\n`;
|
851 |
+
});
|
852 |
+
|
853 |
+
return csvContent;
|
854 |
+
}
|
855 |
|
856 |
+
// Generate chart image as base64
|
857 |
+
function generateChartImage() {
|
858 |
+
if (!liveChart) return null;
|
859 |
+
return liveChart.toBase64Image();
|
860 |
+
}
|
861 |
+
|
862 |
+
// Convert data URL to Blob for file upload
|
863 |
+
function dataURLtoBlob(dataURL) {
|
864 |
+
const arr = dataURL.split(',');
|
865 |
+
const mime = arr[0].match(/:(.*?);/)[1];
|
866 |
+
const bstr = atob(arr[1]);
|
867 |
+
let n = bstr.length;
|
868 |
+
const u8arr = new Uint8Array(n);
|
869 |
+
|
870 |
+
while (n--) {
|
871 |
+
u8arr[n] = bstr.charCodeAt(n);
|
872 |
+
}
|
873 |
+
|
874 |
+
return new Blob([u8arr], { type: mime });
|
875 |
+
}
|
876 |
+
|
877 |
+
// Show alert notification
|
878 |
+
function showAlert(message, type = 'info') {
|
879 |
+
const alertEl = document.createElement('div');
|
880 |
+
alertEl.className = `fixed top-4 right-4 p-4 rounded-lg z-50 ${
|
881 |
+
type === 'error' ? 'bg-danger-600' :
|
882 |
+
type === 'success' ? 'bg-success-600' : 'bg-industrial-600'
|
883 |
+
} text-white shadow-lg`;
|
884 |
+
alertEl.textContent = message;
|
885 |
+
|
886 |
+
document.body.appendChild(alertEl);
|
887 |
+
|
888 |
+
setTimeout(() => {
|
889 |
+
alertEl.classList.add('opacity-0', 'transition-opacity', 'duration-300');
|
890 |
+
setTimeout(() => alertEl.remove(), 300);
|
891 |
+
}, 5000);
|
892 |
+
}
|
893 |
// Get status for history
|
894 |
function getStatus(temp) {
|
895 |
if (temp > 35) return 'critical';
|